1. 問題描述:html
有兩個數組a,b,大小都爲n,數組元素的值任意整形數,無序;
要求:經過交換a,b中的元素,使[數組a元素的和]與[數組b元素的和]之間的差最小。java
2. 求解思路:算法
當前數組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-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爲止。數組
3. C語言實現spa
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #define N 100 5 int A[N]; 6 int B[N]; 7 //隨機初始化一個數組 8 void init(int a[], int n) 9 { 10 int i; 11 for(i = 0; i < n; ++i) 12 a[i] = rand() % N; 13 } 14 //輸出數組 15 void print(int a[], int n) 16 { 17 int i; 18 for(i = 0; i < n; ++i) 19 printf("%d ", a[i]); 20 printf("\n--------------------------------------------\n"); 21 } 22 23 //求數組和 24 int sum(int a[], int n) 25 { 26 int i, sum = 0; 27 for(i = 0; i < n; ++i) 28 sum += a[i]; 29 return sum; 30 } 31 //交換整數 32 void swap(int *a, int *b) 33 { 34 int temp = *a; 35 *a = *b; 36 *b = temp; 37 } 38 //n1,n2爲數組A和B中實際初始化的元素個數 39 int solve(int n1, int n2) 40 { 41 int i, j; //循環迭代變量 42 int x, y; //用於保存可交換數字對的索引 43 int maxSum, minSum; //分別用於保存兩個數組的數字之和 44 int diff; //diff = sum1 - sum2 45 int maxdiff; // 2 * (A[x] - B[y]) 46 int flag; //標記是否找到可交換的數字對 47 int temp; 48 int *pMax; //指向數字總和較大的數組 49 int *pMin; //指向數字總和較小的數組 50 51 //隨機初始化數組 52 init(A, n1); 53 init(B, n2); 54 print(A, n1); 55 print(B, n2); 56 //求數組中數字之和 57 maxSum = sum(A, n1); 58 minSum = sum(B, n2); 59 60 if(maxSum == minSum) 61 { 62 printf("There is no need to swap!\n"); 63 return 0; 64 } 65 66 //令pMax和pMin分別指向數字總和大的數組以及總和小的數組 67 pMax = A; 68 pMin = B; 69 if(maxSum < minSum) 70 { 71 pMax = B; 72 pMin = A; 73 swap(&maxSum, &minSum); 74 } 75 //循環交換兩個數組中的數字對,在交換的過程當中,始終 76 //保持pMax數組的數字總和大於或者等於pMin數組的數字總和。 77 //也就是保持diff >= 0 78 diff = maxSum - minSum; 79 while(1) 80 { 81 flag = 0; 82 x = y = 0; 83 maxdiff = 0; 84 //尋找可以使diff減少的數字對。 85 //從趨勢上來看, 86 //減少的幅度越大diff收斂的越快, 87 //while循環的次數也越少 88 for(i = 0; i < n1; ++i) 89 { 90 for(j = 0; j < n2; ++j) 91 { 92 temp = pMax[i] - pMin[j]; 93 if(temp > 0 && (diff - 2 * temp) >= 0) 94 { 95 if(maxdiff < 2 *temp) 96 { 97 maxdiff = 2 * temp; 98 x = i; 99 y = j; 100 flag = 1; 101 } 102 } 103 } 104 } 105 if(flag) //找到了可使diff減少的數字對 106 { 107 printf("swap, pMax[%d]:%d, pMin[%d]:%d\n", x, pMax[x], y, pMin[y]); 108 diff -= maxdiff; 109 swap(pMax + x, pMin + y); 110 print(A, n1); 111 print(B, n2); 112 printf("diff = %d\n", diff); 113 114 } 115 else //沒有找到能夠交換的數字對,終止while循環 116 { 117 break; 118 } 119 } 120 return diff; //返回兩個數組經交換後的最小差值 121 } 122 123 int main(int argc, char **argv) 124 { 125 126 srand(time(NULL)); 127 printf("min difference:%d\n", solve(5, 5)); 128 // system("pause"); 129 // pause(); 130 return 0; 131 }
4. java實現.net
1 import java.util.Arrays; 2 3 /** 4 * 5 * @author Administrator 6 * 7 */ 8 public class TestUtil { 9 private int[] arrysMin = null; 10 11 private int[] arrysMax = null; 12 13 private int matchNum = 0; 14 15 private boolean hasMatched = false; 16 17 /** 18 * 返回數組的全部元素的總和 19 * 20 * @param arrays 21 * 待計算數組 22 * @return 全部元素的總和值 23 */ 24 public int getArraySum(int[] arrays) { 25 int sum = 0; 26 if (null != arrays) { 27 for (int i : arrays) { 28 sum += i; 29 } 30 } 31 return sum; 32 } 33 34 /** 35 * 返回數組的差值 36 * 37 * @param array1 38 * 集合一 39 * @param array2 40 * 集合二 41 * @return 差值 42 */ 43 public int getTowArraysMacth(int[] array1, int[] array2) { 44 Integer l1 = getArraySum(array1); 45 Integer l2 = getArraySum(array2); 46 47 if ((l1 - l2) / 2 > 0) { 48 arrysMax = array1; 49 arrysMin = array2; 50 return (l1 - l2) / 2; 51 } else { 52 arrysMax = array2; 53 arrysMin = array1; 54 return (l2 - l1) / 2; 55 } 56 } 57 58 private boolean isReturn(int[] arrayMax, int[] arrayMin) { 59 Integer l1 = getArraySum(arrayMax); 60 Integer l2 = getArraySum(arrayMin); 61 62 if ((l1 - l2) > 0) { 63 return false; 64 } else { 65 return true; 66 } 67 } 68 69 public void doMatch() { 70 // 保證大的數組總和永遠是大的,以防遞歸進入死循環 71 if (isReturn(arrysMax, arrysMin)) { 72 return; 73 } 74 // 獲取元素總和大的與小的差值平均值 75 int diff = getTowArraysMacth(arrysMax, arrysMin); 76 // 使用一個大數字初始化最小絕對值,後面作比較 77 int abs = getArraySum(arrysMax); 78 int tempElement = 0; 79 // 最終大數組要交換的下標 80 int maxIndex = -1; 81 int minIndex = -1; 82 if (null != arrysMax && null != arrysMin) { 83 for (int i = 0; i < arrysMax.length; i++) { 84 for (int j = 0; j < arrysMin.length; j++) { 85 int temp = arrysMax[i] - arrysMin[j]; 86 if (temp > 0 && diff > temp) { 87 // 若是元素差值和元素總和大的與小的差值平均值正好相等,直接交換元素OK 88 if (Math.abs(diff - temp) == 0) { 89 tempElement = arrysMin[j]; 90 arrysMin[j] = arrysMax[i]; 91 arrysMax[i] = tempElement; 92 matchNum++; 93 hasMatched = true; 94 return; 95 } else { 96 // 不然徹底遍歷,最終找出元素差值和總和差值平均值差距最小的兩元素, 97 if (abs > Math.abs(diff - temp)) { 98 abs = Math.abs(diff - temp); 99 maxIndex = i; 100 minIndex = j; 101 } 102 } 103 } 104 } 105 } 106 //若是沒有找到匹配項,且在已變換的數組中找到了知足條件的變量,則繼續遞歸 107 if (!hasMatched && (maxIndex != -1 || minIndex != -1)) { 108 // 交換差距最小的兩元素 109 System.out.printf("第%d次交換, Max[%d]:%d, Min[%d]:%d\n", ++matchNum, maxIndex, arrysMax[maxIndex], minIndex, arrysMin[minIndex]); 110 tempElement = arrysMin[minIndex]; 111 arrysMin[minIndex] = arrysMax[maxIndex]; 112 arrysMax[maxIndex] = tempElement; 113 System.out.println("交換後Max數組:" + Arrays.toString(arrysMax)); 114 System.out.println("交換後Min數組:" + Arrays.toString(arrysMin)); 115 System.out.println(); 116 // 遞歸 117 doMatch(); 118 } 119 } 120 } 121 122 public int getMatchNum() { 123 return matchNum; 124 } 125 126 /** 127 * @param args 128 */ 129 public static void main(String[] args) { 130 TestUtil tu = new TestUtil(); 131 int[] a1 = { 11, 2, 4, 6, 47 }; 132 int[] a2 = { 4, 5, 8, 9, 2 }; 133 System.out.println("交換前數組a1:" + Arrays.toString(a1)); 134 System.out.println("交換前數組a2:" + Arrays.toString(a2)); 135 // 進行第一次分出,兩元素的總和誰大誰小 136 tu.getTowArraysMacth(a1, a2); 137 // 開始進行處理交換 138 tu.doMatch(); 139 // 打印交換結果 140 System.out.println("交換次數:" + tu.getMatchNum()); 141 System.out.println("a1數組元素和:" + tu.getArraySum(a1)); 142 System.out.println("a2數組元素和:" + tu.getArraySum(a2)); 143 System.out.println("交換後原數組a1:" + Arrays.toString(a1)); 144 System.out.println("交換後原數組a2:" + Arrays.toString(a2)); 145 } 146 }
參考連接:http://blog.csdn.net/kittyjie/article/details/4386742code
http://www.myexception.cn/program/758365.html (此頁面中的java實現是有問題的,本文已對其做出修改)htm