参考网址:http://blog.csdn.net/v_JULY_v/article/details/6126444 第32题
问题描述:
有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小
代码实现:
#include <cstdio> #include <cstdlib> #include <cmath> void swapi(int *x, int *y); int sum(int a[], int n); int isXinA(int x, int A); void process(int a[], int b[], int n); int main() { int a[] = {1, 2, 3, 29, 30}; int b[] = {1, 210, 232, 12311, 12312}; int n = 5; process(a, b, n); for (int i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); for (int i = 0; i < n; i++) printf("%d ", b[i]); printf("\n%d\n", abs(sum(a, n)- sum(b, n))); system("pause"); return 0; } void swapi(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int sum(int a[], int n) { int ret = 0; for (int i = 0; i < n; i++) ret += a[i]; return ret; } int isXinA(int x, int A) { if ((x>0 && x<A) || (x>A && x<0)) return 0; return 1; } void process(int a[], int b[], int n) { int sum_a = sum(a, n); int sum_b = sum(b, n); int A = sum_a - sum_b; float minValue = abs(a[0]-b[0] - A/2.0); int ii = 0, jj = 0; int flag = 0; if (A == 0) return; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int x = a[i] - b[j]; if (x == 0) continue; if (isXinA(x, A) == 0) { float temp = (float)abs(a[i]-b[j] - A/2.0); if (temp < minValue) { minValue = temp; ii = i; jj = j; flag = 1; } } } } if (flag == 1) { swapi(&a[ii], &b[jj]); process(a, b, n); //继续求解 } } //求解思路: //当前数组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'| = |A| - |A-2x| // //假设A > 0, //当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为止。