有两个数组a,b,大小都为n,数组元素的值任意整形数,无序;
要求:通过交换a,b中的元素,使数组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-2x|<|A|,调换a[i]和b[j]才有意义,此时的条件为:
0<x<A,A>0或者A<x<0,A<0,如果找不符合这样条件的x,则结束调换。
并且当x越接近A/2,效果越好(A‘趋近于0)。
所以算法大概如下:
在a和b中寻找两个数a[i],b[j]使得0<x<A,A>0或者A<x<0,A<0,并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到符合0<x<A,A>0或者A<x<0,A<0的a[i],b[j]为止。
代码如下:
#include<iostream> using namespace std; void minSumDiff(int a[],int b[],int n) { bool unfinish=true; while(unfinish) { unfinish=false; int sumDiffab=0;//存储sum(a)-sum(b)=A for(int i=0;i<n;i++) sumDiffab+=a[i]-b[i]; float halfSum=sumDiffab/2.0;//即A/2 int posa=0,posb=0; float mindis=abs(sumDiffab); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { int x=a[i]-b[j]; if((sumDiffab>0&&x>0&&x<sumDiffab)||(sumDiffab<0&&x<0&&x>sumDiffab))//if(x*sumDiffab>0&&abs(x)<abs(sumDiffab)) //只有满足|A-2x|<|A|,调换才有意义:即A>0时,0<x<A;当A<0时,A<x<0 { unfinish=true; float t=abs(x-halfSum);//计算x与A/2的距离 if(t<mindis)//存储离A/2最近的x的距离值以及对应的调换。 { mindis=t; posa=i; posb=j; } } } } if(unfinish) { int tmp; tmp=a[posa]; a[posa]=b[posb]; b[posb]=tmp; } } } int main() { int a[]={4,3,9}; int b[]={2,1,6}; minSumDiff(a,b,3); for(int i=0;i<3;i++) { cout<<a[i]<<","<<b[i]<<endl; } system("pause"); return 0; }
时间: 2024-10-10 02:31:38