有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小。
例如:
var a=[100,99,98,1,2, 3];
要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小。
例如:
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];
HANDWRITING:
首先求的2数组差D,遍历查找交换一对数a[i],b[j]使得差|D - 2(a[i] - b[j]) |最小,直到不能改变则终止遍历
#define abs(x) (x)>0?(x):-(x)
void search (int *a, int *b, int size) {
int diff = 0, flag;
for (int i = 0; i < size; ++i) diff += a[i] - b[i];
while (1) {
flag = 0;
int min = abs(diff), ma, mb;
for (int apos = 0; apos < size; ++apos)
for (int bpos = 0; bpos < size; ++bpos) {
int tdiff = abs( diff - 2*(a[apos]-b[bpos]) );
if (min > tdiff) {
flag = 1;
min = tdiff;
ma = apos;
mb = bpos;
}
}
if (!flag) break;
a[ma] ^= b[mb];
b[mb] ^= a[ma];
a[ma] ^= b[mb];
diff -= 2*(a[ma] - b[mb]);
}
cout<<diff<<endl;
}
1、a[ma],b[mb]已经交换,diff -= 2*(a[ma] - b[mb])应改成diff += 2*(a[ma] - b[mb]);
2、有缺陷,例如A = { 5,5,9,10 }; B = { 4,7,7,13 }; 交换5,5与4,7可以使得差为0,上述方法无法检测
编程之美上有类似的解答:
原问题可以转换为2n个数,从中选出n个数,使得n个数的和最接近于sum/2,那么剩余的那n个数之和也必定最接近于sum/2。
因此,我们只需找到n个数使得它的和小于sum/2,取其中最大的和。这个问题转换成了0/1背包问题。
空间复杂度为2n * sum/2,但当sum很大时,如数组{10^5, 10^4, 10^3, 10^2}空间浪费相当严重
for (k = 1; k <= 2 * n; k++) {
for (i = 1; (i <= k && i <= n); i++) {
for (v = 1; v <= sum / 2; v++) {
if (v >= arr[k] && isOK[i - 1][v - arr[k] ])
isOK[i][v] = true;
}
}
}
}