dark_ql 发表于 2006-11-18 23:36

int dist = 0;
int temp = 0;
for( int i=0; i<N; i++){
    if( abs(dist+A-B) < abs(dist+B-A) ){
          dist += A-B;
    }else{
          change(A,B);
          dist += A-B;
    }
}


说明:上述程序的目标是使交换后A数组的和减去B数组的和的绝对值最小,也就是两者之间相差最少
最终dist保存的即为两者之间的差
我就写了个例子验证了一下上述程序
A:2   4    5    8
B:1   7    6    9
按照上述规则,交换5-6,8-9,最终dist==0
如有错误请大家指出

[ 本帖最后由 dark_ql 于 2006-11-18 23:59 编辑 ]

svenwang 发表于 2006-11-19 00:00

这个帖子有点无聊了。很多人都只看第一贴,自己重复了别人的错误还不知道。
要是说是微软面试题估计更火爆。

erduo100 发表于 2006-11-19 10:24

没想出好的算法 我的思路把2n个数放在一个数组里 然后用组合找出n个数 求和 另n个数也求和 做查
求出所有这样的差值的最小值,故复杂度为theta( C(2n, n))再把原数组的值经过有限次的交换 调整成最优解的数组值就行了
其中C(2n, n)用的是回溯 构架是

void select_combination(int l, int p)
{
        int i;

        if (l == n)
        {
                。。。
                return;
        }

        for(i=p; i<=2*n-(n-l); ++i) //上个位置填的是num,本次从num开始试探
        {
                b = true;
                select_combination(l+1, i+1); //填下一个位置
                b = false;
        }
}


下面是整个程序

#include <stdio.h>
#include <math.h>

const int n = 3;
int num;
bool b;
bool bc;
bool first = true;
int de, sumae, sumbe;
int mins;

void copy(bool p[], bool q[], int n)
{
        for (int i = 0; i < n; ++i)
        {
                q = p;
        }
}

void select_combination(int l, int p)
{
        int i;

        if (l == n)
        {
                int suma = 0, sumb = 0;
                for (i=0; i<2*n; ++i)
                {
                        if (b)
                                suma += num;
                        else
                                sumb += num;                       
                }


                if (first)
                {
                        first = false;
                        mins = abs(suma - sumb);
                        de = mins;
                        sumae = suma;
                        sumbe = sumb;                       
                }
               
                else
                {
                        int d = abs(suma - sumb);
                        if (d < mins)
                        {
                                mins = d;
                                copy(b, bc, 2*n);
                                de = mins;
                                sumae = suma;
                                sumbe = sumb;
                        }
                }

                return;
        }

        for(i=p; i<=2*n-(n-l); ++i) //上个位置填的是num,本次从num开始试探
        {
                b = true;
                select_combination(l+1, i+1); //填下一个位置
                b = false;
        }
}

bool find(int a[], int n, int va, int& pos)
{
        for (int i = 0; i < n; ++i)
        {
                if (va == a)
                {
                        pos = i;
                        return true;
                }
        }

        return false;
}
void swap(int& a, int& b)
{
        int tem = a;
        a = b;
        b = tem;
}

int main()
{
        int a = {1,4, 7};
        int c = {2,5,12};
        int i, suma = 0, sumc = 0;
        for (i = 0; i < 2*n; ++i)
        {
                if (i < n)
                {
                        num = a;
                        suma += a;
                }

                else
                {
                        num = c;
                        sumc += c;
                }
               
                b = false;
        }
        select_combination(0, 0);

        // 下面是追踪交换的顺序
        int ac, cc, p = 0, q = 0;
        for (i = 0; i < 2*n; ++i)
        {
                if (bc)
                        ac = num;

                else
                        cc = num;
        }

        p = 0;
        int pos;
       
        // 使a中的值与ac中的值相同
        while (p < n)
        {
                if (a == ac)
                {
                        ++p;
                        continue;
                }

                else
                {

                        if (find(c, n, ac, pos))
                        {
                                printf("swap %d in a[%d] and %d in c[%d]\n",
                                                 a,   p,      c,pos);
                                swap(a, c);
                        }

                        // a 一定在数组a里 需交换3次
                        else
                        {
                                find(a, n, ac, pos);

                                printf("swap %d in a[%d] and %d in c[%d]\n",
                                                 a,   p,      c,0);
                                swap(a, c);

                                printf("swap %d in a[%d] and %d in c[%d]\n",
                                                 a,   pos,      c,0);
                                swap(a, c);

                                printf("swap %d in a[%d] and %d in c[%d]\n",
                                                 a,   p,      c,0);
                                swap(a, c);
                        }
                }
       
                ++p;
        }

        // 使c中的值与cc中的值相同
        q = 0;
        while (q < n)
        {
                if (c == cc)
                {
                        ++q;
                        continue;
                }

                else
                {
                        find(c, n, cc, pos);

                        printf("swap %d in c[%d] and %d in a[%d]\n",
                                             c,   q,      a,0);
                        swap(c, a);

                        printf("swap %d in c[%d] and %d in a[%d]\n",
                                             c,   pos,      a,0);
                        swap(c, a);

                        printf("swap %d in c[%d] and %d in a[%d]\n",
                                             c,   q,      a,0);
                        swap(c, a);

                }
                ++q;
        }
        printf("\n交换前suma: %d, sumb: %d\n", suma, sumc);

        printf("交换后suma: %d, sumb: %d\n", sumae, sumbe);

        return 0;
}

wswn5456 发表于 2006-11-20 02:17

原帖由 mike_chen 于 2006-11-13 09:34 发表
放到一个临时数组里排序后,两头取,分别存在a,b里

我同意这个

lknh17 发表于 2006-11-20 06:27

你们还在讨论这个问题呢...题说交换,又没说要给出交换的过程。。所以完整程序很简单......变个思维想想么
呵呵

lknh17 发表于 2006-11-20 06:39

另外,xmyth 的算法是基于贪心的,所以并不是最优的,只不过大多时候是最优的而已

lknh17 发表于 2006-11-20 06:44

再罗嗦点.....认清此题问题本是NP问题,就不会去想一些自以为很好的算法了
老老实实回朔剪枝吧,此题剪枝才是优化的王道,目前我用了3处剪枝已经将速度加速了很多
比较遗憾的是题目没给n范围,所以不好考虑剪枝的代价,所以我认为不给出n的规模此题写起来没什么意义,
所以代码也就不贴了。。。。

tank1111 发表于 2006-11-20 13:01

参加tyc611 的帖子
发现xmyth算法的模型还是有问题,如tyc611的例子,同时交换不能只限于一个元素

我的想法:
也许可以拓展成只要找到x在(0, A], 合集,不是开集,就进行交换

例子如下:
3,5,6,7,13,14   sum = 48
1,3,7,8,10,17   sum = 46

因为a - b = 2,在(0, 2]之间, 且没有更逼近于A/2的选择,故交换之

3,3,7,8,10,17    sum = 48
1,5,6,7,13,14    sum = 46
现在a - b = 1, 在(0,2]之间, 交换

3,3,6,8,10,17  sum = 47
1,5,7,7,13,14    sum = 47

得到最佳结果

xmyth 发表于 2006-11-20 16:56

我前面提出的算法的确是错误的,贪婪算法在这种情况下不可行。

而楼上的想法也是错误的,比如这个简单的例子就行不通了

a = {11,12,8,91}
b = {1,2,17,100}

动态规划算法对这个题目应该是适用的
该题等价于在2n中元素中选取n个元素,使得这n个元素的和最接近于2n个元素总和的一半

/*
* 在数组c中的n个元素中选取m个元素,使得这m个元素的和最接近y
* func(c, n, m, y) 就表示这m个元素的和
* 然后通过比较func(c, n, m, y) 和 func(c + 1, n - 1, m, y) 就可以确定选取的这m个元素是哪几个
*/

func(int *c, int n, int m, int y) {
if (m == 0)
    return 0;
if (n == m)
    return sum(c, n);
a = func(c + 1, n - 1, m, y);
b = func(c + 1, n - 1, m - 1, y - *c) + *c;
return abs(y - a) <= abs(y - b) ? a:b;
}

[ 本帖最后由 xmyth 于 2006-11-21 21:01 编辑 ]

新新手 发表于 2006-11-20 18:36

页: 4 5 6 7 8 9 10 11 12 13 [14] 15 16 17 18 19 20 21 22 23
查看完整版本: 华为面试题(8分钟写出代码)