這個題目是在網上看到了,題目描述如下:有兩個數組a,b,大小都為n,數組元素的值任意,無序。要求:通過交換a,b中的元素,使數組a元素的和與數組b元素的和之間的差最小。不知道是否真的出自華為,但題目難度很大,以我的水平8分鍾確實無法寫出完整的代碼,查閱網上的牛人的思路,理解整理如下:
- 對兩個數字值進行累加,設差值 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為止。根據算法描述實現代碼:
1 int SwapArray(int *a, int *b, int n) 2 { 3 int nSumA=0, nSumB=0; //分別記錄兩個數組的和
4 int nSumDiff=0, nNumDiff=0; //nSumDiff表示每輪數組和的差值,nNumDiff表示每輪數組各選兩數之差
5
6 float dHalfDiffSum=0.0f, dClose2SumDiff=0.0f; //dHalfDiffSum表示nSumDiff/2, dClose2SumDiff表示每輪最接近dHalfDiffSum的數
7
8 int nIndexI=0, nIndexJ=0; 9 bool bDesc=false, bSwitch=false; //bDesc為true表示 nSumA > nSumB,bSiwtch為true表示 nNumDiff < nSumDiff,此輪無需交換
10
11 int i=0, j=0; 12 while(1) 13 { 14 for(i=0; i!=n; i++) 15 { 16 nSumA += a[i]; 17 nSumB += b[i]; 18 } 19 nSumDiff = nSumA - nSumB; 20 dHalfDiffSum = (float)nSumDiff/2; 21 dClose2SumDiff = dHalfDiffSum; 22 bDesc = nSumA >= nSumB? true : false; 23 if(bDesc) 24 { 25 for(i=0; i!=n; i++) 26 for(j=0; j!=n; j++) 27 { 28 nNumDiff = a[i]-b[j]; 29 cout<<__LINE__<<" nSumDiff = "<<nSumDiff<<" dHalfDiffSum = "<<dHalfDiffSum<<" "<<"dClose2SumDiff = "<<dClose2SumDiff<<" "<<"nNumDiff = "<<nNumDiff<<endl; 30 //當在SumA>SumB時,考慮滿足交換的條件:1. a[i]<b[j]此時交換只會使SumA更大於SumB,使得SumA-SumB>nSumDiff 2. a[i]-b[j]>SumA-Sumb此時交換同樣使得|SumA-SumB|>nSumDiff,這兩者條件下都會使兩個數組差值越來越大,故需要進行如下過濾
31 if(nNumDiff > 0 && nNumDiff < nSumDiff) 32 { 33 if(nNumDiff >= dHalfDiffSum) 34 { 35 if(nNumDiff - dHalfDiffSum < dClose2SumDiff) 36 { 37 bSwitch = true; 38 dClose2SumDiff = nNumDiff- dHalfDiffSum; 39 nIndexI = i; 40 nIndexJ = j; 41 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl; 42 } 43 } 44 else
45 { 46 if(dHalfDiffSum - nNumDiff < dClose2SumDiff) 47 { 48 bSwitch = true; 49 dClose2SumDiff = dHalfDiffSum - nNumDiff; 50 nIndexI = i; 51 nIndexJ = j; 52 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl; 53 } 54 } 55 } 56 } 57 } 58 else
59 { 60 for(i=0; i!=n; i++) 61 for(j=0; j!=n; j++) 62 { 63 nNumDiff = a[i]-b[j]; 64 cout<<__LINE__<<" nSumDiff = "<<nSumDiff<<" dHalfDiffSum = "<<dHalfDiffSum<<" "<<"dClose2SumDiff = "<<dClose2SumDiff<<" "<<"nNumDiff = "<<nNumDiff<<endl; 65 if(nNumDiff < 0 && nNumDiff < nSumDiff) 66 { 67 if(nNumDiff > dHalfDiffSum) 68 { 69 if(nNumDiff - dHalfDiffSum < dClose2SumDiff) 70 { 71 bSwitch = true; 72 dClose2SumDiff = nNumDiff-dHalfDiffSum; 73 nIndexI = i; 74 nIndexJ = j; 75 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl; 76 } 77 } 78 else
79 { 80 if(dHalfDiffSum - nNumDiff < dClose2SumDiff) 81 { 82 bSwitch = true; 83 dClose2SumDiff = dHalfDiffSum-nNumDiff; 84 nIndexI = i; 85 nIndexJ = j; 86 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl; 87 } 88 } 89 } 90 } 91 } 92
93 if(!bSwitch) 94 break; 95
96 swap(a[nIndexI], b[nIndexJ]); 97
98 for(i=0; i!=n; i++) 99 cout<<a[i]<<" "; 100 cout<<endl; 101
102 for(i=0; i!=n; i++) 103 cout<<b[i]<<" "; 104 cout<<endl; 105
106 nSumA = nSumB =0; 107 bDesc = bSwitch = false; 108 } 109
110 return 0; 111 } 112
113 int _tmain(int argc, _TCHAR* argv[]) 114 { 115 int a[] = {5, 10,22}; 116 int b[] = {1, 4, 3}; 117
118 SwapArray(a, b, 3); 119
120 return 0; 121 }