两个序列最大子集公共和问题

前几天听同学说起这样一个问题,说有两堆物品,分别从两堆物品中挑出一些物品,使这些物品重量之和相同,要求使重量之和最大。我把这个问题抽象出来后是这样子:有两个序列,从两个序列中各选出一些元素组成子序列,使这两个子序列的和相等,要求使子序列的和最大。

我设计的算法如下:

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 }
原文地址:https://www.cnblogs.com/kevinGaoblog/p/2489362.html