您的位置:首页 > 其它

每天学习一算法系列(29)(有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小)

2011-08-19 12:09 573 查看
题目:

有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小。

例如:

var a = [100,99,98,1,2, 3];

var b = [1, 2, 3, 4,5,40];

最后的结果为:

var a = [1,99,98,1,2,2];

var b = [100, 3,3,4,5,40];

思路一:

首先先计算a,b中元素和之间的差绝对值ABDis,然后逐一的把a中的元素和b中的任一元素作比较,如果它们交换后的差值绝对值ABTempDis小于原来的值ABDis,那么就把a,b交换,并重新计算a和b的绝对值,这种动作反复的进行,直到a中任一的元素都不能和b中的任一元素交换为止。(其实是穷举法)

代码如下:

/*-------------------------------
Copyright by yuucyf.   2011.08.19
--------------------------------*/

#include "stdafx.h"
#include <iostream>
#include <assert.h>
using namespace std;

__int64 MakeSmallly(int *pA, int i32ALen, int *pB, int i32BLen)
{
assert(pA);
assert(pB);
assert(i32ALen > 0);
assert(i32BLen > 0);

int i32I = 0, i32J = 0, i32Temp = 0;
__int64 i64ASum = 0, i64BSum = 0;
__int64 i64ABDis = 0, i64TempDis = 0;
for (i32I = 0; i32I < i32ALen; i32I++)
i64ASum += pA[i32I];
for (i32I = 0; i32I < i32BLen; i32I++)
i64BSum += pB[i32I];
i64ABDis = _abs64(i64ASum - i64BSum);

bool bSwap = false;
for (i32I = 0; i32I < i32ALen; i32I++)
{
while (true)
{
for (i32J = 0; i32J < i32BLen; i32J++)
{
i64TempDis = _abs64((i64ASum - pA[i32I] + pB[i32J]) -
(i64BSum - pB[i32J] + pA[i32I]));
if (i64TempDis < i64ABDis)
{
i64ASum += (pB[i32J] - pA[i32I]);
i64BSum += (pA[i32I] - pB[i32J]);

i64ABDis = i64TempDis;

i32Temp = pA[i32I];
pA[i32I] = pB[i32J];
pB[i32J] = i32Temp;
bSwap = true;
break;
}
}

if (i32J >= i32BLen)
break;
}

//如果有交换,且i32ALen的值为最后一个元素,
//那么我们必须重新再来一遍,直到没有元素交换为止.
if ((i32I == i32ALen - 1) && bSwap)
{
bSwap = false;
i32I = -1;
}
}

return i64ABDis;
}

int _tmain(int argc, _TCHAR* argv[])
{
int aryA[] = {100, 99, 98, 1, 2, 3};
int aryB[] = {1, 2, 3, 4, 5, 40};
__int64 i64Dis = MakeSmallly(aryA, sizeof(aryA)/sizeof(aryA[0]), aryB, sizeof(aryB)/sizeof(aryB[0]));

cout << "A,B系列元素的最小差为:" << i64Dis << ",最后的结果为,A系列元素为";
for (int i32I = 0; i32I < sizeof(aryA)/sizeof(aryA[0]); i32I++)
cout << aryA[i32I] << " ";
cout << ",B系列元素为";
for (int i32I = 0; i32I < sizeof(aryB)/sizeof(aryB[0]); i32I++)
cout << aryB[i32I] << " ";
cout << endl;

return 0;
}


思路二:

当前数组a和数组b的和之差为A = sum(a) - sum(b),a的第i个元素和b的第j个元素交换后,a和b的和之差为

A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i])

= sum(a) - sum(b) - 2 (a[i] - b[j])

= A - 2 (a[i] - b[j])

设x = a[i] - b[j],那么

A' = |A - 2x|,当然A' 越小也好,所以当x 在 (0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好,如果找不到在(0,A)之间的x,则当前的a和b就是答案。

所以算法大概如下:在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。

代码和思路给出的代码差不多,这里就不给出代码了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐