日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

平衡集合

發布時間:2024/9/30 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 平衡集合 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://blog.csdn.net/v_JULY_v/article/details/6126444的第32題

有兩個序列a,b,大小都為n,序列元素的值任意整數,無序;
要求:通過交換a,b中的元素,使[序列a元素的和]與[序列b元素的和]之間的差最小。
例如:
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];


上面的兩種算法應該都有點問題。

http://blog.csdn.net/cwqbuptcwqbupt/article/details/7521733

因為一次只允許交換一對元素,這對于一次需要交換兩個元素的數組而言將出錯,考慮如下情況:
A = { 5,5,9,10 };
B = { 4,7,7,13 };
A的和為29,B為31。當把A中的5,5與B中的4,7交換后,A與B的和都為30,差為0.但上述算法一將檢測不到這種交換!因此輸出結果是原數組。


可以用一種搜索算法

http://blog.csdn.net/ljsspace/article/details/6434621#

有兩個序列a,b,大小都為n,序列元素的值任意整數,無序;
要求:通過交換a,b中的元素,使[序列a元素的和]與[序列b元素的和]之間的差最小。
例如:??
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];

?

分析:

通過交換的方式,最終的狀態是在保證兩個序列中元素個數相同的條件下,任何一個元素都可以位于兩個序列中的任何一個。這樣問題可以轉化為:在一個長度為2*n的整數序列中,如何將元素個數分成兩個子集,記每個子集的元素之和分別為S1和S2,使得|S1-S2|最小。顯然這是一個最優化問題,如果用brute-force方法,組合數是C(2n,n)=(2n)!/(2*(n!)), 如果n很大這個方法不奏效。

?

這里采用回溯法(backtracking),即前序(preorder)遍歷狀態空間樹(state-space tree)。難點在于剪枝條件的確定,下面說明如何確定剪枝條件:

注意到如果將原序列按從小到大的順序排好序,每次從較大的元素開始取,可以得到一個這樣的規律:設長度為2*n序列的元素總和為Sigma,當前集合元素的和為S,剩下的元素之和為Sigma-S,如果二者滿足S>=Sigma-S,即Sigma<=2*S,那么在當前集合中剩下需要添加進來的元素必須從余下的元素中取最小的那些元素,這樣才能保證|S1-S2|最小。這是因為如果在下一次任意從余下的元素中取的元素分別為e和f,那么取e后的兩個子集差為(S+e) - (Sigma-S-e) = 2S-Sigma +2e,取f后的兩個子集差為2S-Sigma +2f,顯然如果e>f>0, 則有前者的子集差大于后者的子集差(注意這里假設元素都為非負整數,原序列中有負數的情況參考下面的討論)。

如果s<sigma/2, 就要遞歸考慮在加入當前值或者不加入當前值的情況

?

如果輸入序列中有負整數,可以通過平移操作轉化為非負,因為每個數都平移了,它們的差值保值不變。如果不平移,結果不一定正確,比如:輸入的2*n序列為:-10,5,3,20,25,50,平衡的對半子集應該為[-10,5,50]和[3,20,25],差值的絕對值為3。在下面的實現中,如果不考慮平移,得到的錯誤結果卻是[-10,3,50]和[5,20,25],差值的絕對值為7。

?

另外在狀態空間樹只需要考慮根節點的左枝子樹,因為原問題考慮的是對半子集。


import java.util.Arrays; import java.util.Stack; /*** * @author ljs * 2011-05-20* 平衡集合問題**/ public class BalancedSet {//the offset to eliminate negative integersint OFFSET;int[] A;//the total value of the two setsint sigma;//the number of elements in each setint N;//positive valueint minDiff=Integer.MAX_VALUE;Stack<Integer> tracer = new Stack<Integer>();Stack<Integer> bestDiffStack = new Stack<Integer>();public BalancedSet(int[] A) throws Exception{this.A = A;this.init(); }private void init() throws Exception{if(A.length % 2 != 0)throw new Exception();N = A.length / 2; //sort A in ascending orderArrays.sort(A);//offset if possibleif(A[0]<0){OFFSET = -A[0];for(int i=0;i<A.length;i++){A[i] += OFFSET;}}//sigma is the total value after offset is donefor(int i=0;i<A.length;i++){sigma += A[i];} }private void print(){System.out.format("best partition difference is: %d%n",minDiff);//caculate the difference of two setsint[] P = new int[N];int p=0;int i=0,j=bestDiffStack.size()-1;//note: bestDiffStack is in descending order, we need an ascending order to compare with A for(;i<A.length && j>=0;){if(A[i]==bestDiffStack.get(j)){i++;j--;}else if(A[i] < bestDiffStack.get(j)){P[p++] = A[i++];}//else: impossible case }if(i<A.length){P[p++] = A[i++];}System.out.println("One set is: ");while(!bestDiffStack.isEmpty())System.out.format(" %2d",bestDiffStack.pop()-OFFSET); System.out.println();System.out.println("Another set is: ");for(p=0;p<N;p++){System.out.format(" %2d",P[p]-OFFSET); }}public void solve(int[] A){//the first node is not needed to analyse the include=false casecheck(A.length-1, 0, 0, true);print();}//A is sorted in ascending order//count: the searched number of elements (<=N)//include: is the element i included in the setprivate void check(int i,int sum,int count,boolean include){ if(include){//record the nodetracer.push(A[i]);sum += A[i];count++;}if(count==N){int diff = Math.abs(2*sum- sigma);if(diff < minDiff){minDiff = diff; //record the best nodes until nowbestDiffStack.clear();for(Integer k:tracer){bestDiffStack.add(k);}}//else: just throw away this combination }else{if(sigma<=2*sum){//prune the tree: choose the remaining least numbersint remainCount = N-count;for(int j=0;j<remainCount;j++){sum += A[j];}int diff = Math.abs(2*sum- sigma);if(diff < minDiff){minDiff = diff;//record the nodes "1...remainCount"bestDiffStack.clear();for(Integer k:tracer){bestDiffStack.add(k);}for(int j=remainCount-1;j>=0;j--){bestDiffStack.push(A[j]);} }//else: just throw away this combination }else{if(i>=1){//traverse the next subtrees in the state-space treecheck(i-1,sum,count,true);check(i-1,sum,count,false);}//else: the check is invalid }}if(include)//backtrackingtracer.pop();}public static void main(String[] args) throws Exception {int A[] = {3,5,-10,20,25,50}; //int A[] = {3,5,10,20,25,50}; //int A[] = {100,99,98,1,2,3,1,2,3,4,5,40};BalancedSet bs = new BalancedSet(A);bs.solve(A);} }


總結

以上是生活随笔為你收集整理的平衡集合的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。