序列和之差最小

来源:互联网 发布:上海811所硕士待遇知乎 编辑:程序博客网 时间:2024/05/05 07:42

问题:

有两个序列a,b,大小都为n,序列元素的值任意整数,无序;

要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
例如:   
var a=[100,99,98,1,2, 3];

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


分析

我一开始是这么想的:循环试探a和b中元素,每次试探一个,如果和之差变小了,那么就交换元素!

代码:

#include <stdio.h>#include <math.h>#define N 6int a[10],b[10];void Exchange();void Output(int *p);int main(){int i;FILE *infile=fopen("E://a.txt","r");if (!infile){printf("The file cannot be opened!\n");return 0;}for (i=0;i<N;i++){fscanf(infile,"%d",&a[i]);}for (i=0;i<N;i++){fscanf(infile,"%d",&b[i]);}printf("Before change ,the two array are:\n");Output(a);Output(b);Exchange();printf("After change ,the two array are:\n");Output(a);Output(b);return 0;}void Exchange(){int iMinSub,iSumA,iSumB,i,j,iTemp,iTempSub;iSumA=iSumB=0;for (i=0;i<N;i++){iSumA+=a[i];iSumB+=b[i];}iMinSub=labs(iSumA-iSumB);for (i=0;i<N;i++){for (j=0;j<N;j++){iTempSub=labs(iSumA-a[i]+b[j]-(iSumB-b[j]+a[i]));if (iTempSub<iMinSub){iMinSub=iTempSub;iTemp=a[i];a[i]=b[j];b[j]=iTemp;}}}}void Output(int *p){int i;for (i=0;i<N;i++){printf("%d  ",p[i]);}printf("\n");}

后来在网上看到这样的一句话:

你的做法只是每次交换一个就做判断,如果每次交换两个后做判断呢?
如果两个序列分别是[-3,9,10,65]和[5,6,13,55],按你的算法这就是最优解了。可是显然[-3,5,13,65]和[6,9,10,55]更好。

所以这个算法还是有问题的!


换种想法:

当前数组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为止。
算法一(我写的):
#include <stdio.h>#include <math.h>#define N 4int a[10],b[10];void Exchange();void Output(int *p);int main(){int i;FILE *infile=fopen("E://a.txt","r");if (!infile){printf("The file cannot be opened!\n");return 0;}for (i=0;i<N;i++){fscanf(infile,"%d",&a[i]);}for (i=0;i<N;i++){fscanf(infile,"%d",&b[i]);}printf("Before change ,the two array are:\n");Output(a);Output(b);Exchange();printf("After change ,the two array are:\n");Output(a);Output(b);return 0;}void Exchange(){int iMinSub,iSumA,iSumB,i,j,x,iTemp,isChange;iSumA=iSumB=0;for (i=0;i<N;i++)  //calculate sum{iSumA+=a[i];iSumB+=b[i];}iMinSub=iSumA-iSumB; //calculate subtract of two arrayfor (i=0;i<N;i++){for (j=0;j<N;j++){isChange=0;   //judge if change two numberx=a[i]-b[j];  if (iMinSub>0){if (x>0&&x<iMinSub)  //0<x<A{isChange=1;}}else{if (x>iMinSub&&i<0)  //A<x<0{isChange=1;}}if (isChange){iTemp=a[i];a[i]=b[j];b[j]=iTemp;iMinSub-=2*x;   }}}}void Output(int *p){int i;for (i=0;i<N;i++){printf("%d  ",p[i]);}printf("\n");}


算法二(网上找的):

def mean(a, b):    if sum(a) < sum(b):        array = a        a = b        b = array    diff_sum = sum(a) - sum(b)    loop = True    while loop:        loop = False        md = diff_sum / 2        for i in range(0, len(a)):            for j in range(0, len(b)):                x = a[i] - b[j]                if x < diff_sum and x > 0:                    loop = True                    if abs(x - diff_sum / 2) < md:                        md = abs (x - diff_sum / 2)                        mi = i                        mj = j        if loop:            tmp = a[mi]            a[mi] = b[mj]            b[mj] = tmp            diff_sum = diff_sum - 2 * (b[mj] - a[mi])            if diff_sum < 0:                array = a                a = b                b = array                diff_sum = - diff_sumdef main():    a = [7, 9, 10]    b = [6, 2, 8]    mean(a, b)    print (a)    print (b)if __name__ == '__main__':    main()


程序如下:

#include <stdio.h>#define N 3int sum(int *a){int Sum=0,i;for (i=0;i<N;i++){Sum+=a[i];}return Sum;}void Exchange(int *a,int *b){int *array,diff_sum,loop;int i,j,x,tmp;if (sum(a)<sum(b)){array=a;a=b;b=array;}diff_sum=sum(a)-sum(b); loop=1;while (loop){loop=0;for (i=0;i<N;i++){for (j=0;j<N;j++){x=a[i]-b[j];if (x<diff_sum&&x>0){loop=1;tmp=a[i];a[i]=b[j];b[j]=tmp;diff_sum=diff_sum-2*(b[j]-a[i]);if (diff_sum<0){array=a;a=b;b=array;diff_sum=-diff_sum;}}}}}printf("After change,the items are: \n");for (i=0;i<N;i++){printf("%d  ",a[i]);}printf("\n");for (i=0;i<N;i++){printf("%d  ",b[i]);}printf("\n");}int main(){int i;int a[N]={7,9,10};int b[N]={6,2,8};printf("Before change,the items are: \n");for (i=0;i<N;i++){printf("%d  ",a[i]);}printf("\n");for (i=0;i<N;i++){printf("%d  ",b[i]);}printf("\n");Exchange(a,b);return 0;}

不知为何,还是得不出那个理想结果!

先放一下吧。。。