两个序列最大子集公共和问题
前几天听同学说起这样一个问题,说有两堆物品,分别从两堆物品中挑出一些物品,使这些物品重量之和相同,要求使重量之和最大。我把这个问题抽象出来后是这样子:有两个序列,从两个序列中各选出一些元素组成子序列,使这两个子序列的和相等,要求使子序列的和最大。
我设计的算法如下:
1.两个序列选择子序列按照0-1方式生成解空间。所以按回溯方式遍历解空间。
2.要实现高效得考虑贪心性。
3.序列和小的序列的和很大概率上就是两个序列的最大子集公共和。
4.序列和小的序列做基础。
5.对原序列排序,如果较密集,小序列用降序排列。如果两个序列和的差较大,大序列用升序排列。
1 #include "stdafx.h" 2 #include <iostream> 3 using std::cout; 4 5 const int VALUE=1000; 6 7 /*为方便,用全局变量做实验*/ 8 9 int cSumA=0;//当前过程中A的被检验的和 10 int cSumB=0;//当前过程中B的被检验的和 11 int rSumA=0;//当前过程中A中剩余元素的总和 12 int rSumB=0;//当前过程中B中剩余元素的总和 13 14 int sumA=0;//A序列的和 15 int sumB=0;//B序列的和 16 int comSum=0;//当前过程中记录的最优子集公共和 17 18 const int aSize=10; 19 const int bSize=10; 20 int A[aSize+1]={0, 221,411,345,926,451,1425,882, 1213,453,782}; 21 int B[bSize+1]={0,45,664,1121,551,144,489,841,1120,356,1245}; 22 int *a; 23 int *b; 24 int tempsubA[aSize+1]={0}; 25 int tempsubB[bSize+1]={0}; 26 27 int resultsubA[aSize+1]={0}; 28 int resultsubB[bSize+1]={0}; 29 30 void BacktrackSumA(int i); //回溯遍历法 31 void BacktrackSumB(int i); 32 33 //快速排序的patition,Ds为降序 34 int patitionDs( int arr[],int left , int right ) 35 { 36 int pivot=arr[left]; 37 while(left<right) 38 { 39 while(left<right&&arr[right]<=pivot) 40 right--; 41 arr[left]=arr[right]; 42 while(left<right&&arr[left]>=pivot) 43 left++; 44 arr[right]=arr[left]; 45 } 46 arr[left]=pivot; 47 return left; 48 } 49 //快速排序,降序 50 void quickSortDs( int arr[], int left, int right ) 51 { 52 int pivot; 53 if(left<right) 54 { 55 pivot=patitionDs( arr,left,right); 56 quickSortDs( arr, left, pivot-1); 57 quickSortDs(arr, pivot+1,right); 58 } 59 } 60 61 int patitionAs( int arr[],int left , int right ) 62 { 63 int pivot=arr[left]; 64 while(left<right) 65 { 66 while(left<right&&arr[right]>=pivot) 67 right--; 68 arr[left]=arr[right]; 69 while(left<right&&arr[left]<=pivot) 70 left++; 71 arr[right]=arr[left]; 72 } 73 arr[left]=pivot; 74 return left; 75 } 76 77 void quickSortAs( int arr[], int left, int right ) 78 { 79 int pivot; 80 if(left<right) 81 { 82 pivot=patitionAs( arr,left,right); 83 quickSortAs( arr, left, pivot-1); 84 quickSortAs(arr, pivot+1,right); 85 } 86 } 87 88 //获取A序列的和。 89 void getSumA() 90 { 91 for(int i=1;i<=aSize;i++) 92 sumA=rSumA+=A[i]; 93 } 94 95 void getSumB() 96 { 97 for(int i=1;i<=bSize;i++) 98 sumB=rSumB+=B[i]; 99 } 100 101 //回溯法遍历A的解空间 102 void BacktrackSumA(int i) 103 { 104 if(i>aSize) 105 {
if(cSumA>comSum && cSumA<=sumB) 106 {
rSumB=sumB; 107 BacktrackSumB(1); 108 int f=0; 109 } 110 return; 111 } 112 if(cSumA+rSumA>comSum) 113 { 114 rSumA-=a[i]; 115 116 cSumA+=a[i]; 117 tempsubA[i]=a[i]; 118 BacktrackSumA(i+1); //系数xi取1 119 tempsubA[i]=0; 120 cSumA-=a[i]; 121 122 BacktrackSumA(i+1); //系数xi取0 123 124 rSumA+=a[i]; 125 } 126 } 127 128 void BacktrackSumB( int i) 129 { 130 if(i>bSize) 131 return; 132 if(cSumB+rSumB>=cSumA) 133 { 134 rSumB-=b[i]; 135 if(cSumB+b[i]==cSumA) 136 { 137 for(int j=0;j<=aSize;j++) 138 resultsubA[j]=tempsubA[j]; 139 for(int j=0;j<bSize;j++) 140 resultsubB[j]=tempsubB[j]; 141 resultsubB[i]=b[i]; 142 comSum=cSumA; 143 return; 144 } 145 if(cSumB+b[i]<cSumA) //系数yi取1 146 { 147 cSumB+=b[i]; 148 tempsubB[i]=b[i]; 149 BacktrackSumB(i+1); 150 cSumB-=b[i]; 151 tempsubB[i]=0; 152 } 153 BacktrackSumB(i+1); //系数yi取0 154 rSumB+=b[i]; 155 } 156 } 157 158 int _tmain(int argc, _TCHAR* argv[]) 159 { 160 getSumA(); 161 getSumB(); 162 if(sumA<sumB) 163 { 164 a=A; 165 b=B; 166 } 167 else 168 { 169 int tem=sumA; 170 sumA=rSumA=sumB; 171 sumB=rSumB=tem; 172 a=B; 173 b=A; 174 } 175 if(sumB-sumA>VALUE) //用VALUE做阀值,以确定用哪种排序 176 { 177 quickSortAs( a, 1,aSize); 178 quickSortAs( b, 1,bSize); 179 } 180 else 181 { 182 quickSortDs( a, 1,aSize); 183 quickSortDs( b, 1,bSize); 184 } 185 BacktrackSumA(1); 186 cout<<comSum; 187 188 getchar(); 189 return 0; 190 }
**************************************************************
我喜欢程序员,他们单纯、固执、容易体会到成就感;面对困难,能够不休不眠;面对压力,能够迎接挑战。他们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想,用智慧把属于自己的事业开创。其实我是一个程序员[=.=]
我喜欢程序员,他们单纯、固执、容易体会到成就感;面对困难,能够不休不眠;面对压力,能够迎接挑战。他们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想,用智慧把属于自己的事业开创。其实我是一个程序员[=.=]