您的位置:首页 > 其它

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

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

我设计的算法如下:

1.两个序列选择子序列按照0-1方式生成解空间。所以按回溯方式遍历解空间。

2.要实现高效得考虑贪心性。

3.序列和小的序列的和很大概率上就是两个序列的最大子集公共和。

4.序列和小的序列做基础。

5.对原序列排序,如果较密集,小序列用降序排列。如果两个序列和的差较大,大序列用升序排列。

#include "stdafx.h"
#include <iostream>
using std::cout;

const int VALUE=1000;

/*为方便,用全局变量做实验*/

int cSumA=0;//当前过程中A的被检验的和
int cSumB=0;//当前过程中B的被检验的和
int rSumA=0;//当前过程中A中剩余元素的总和
int rSumB=0;//当前过程中B中剩余元素的总和

int sumA=0;//A序列的和
int sumB=0;//B序列的和
int comSum=0;//当前过程中记录的最优子集公共和

const int aSize=10;
const int bSize=10;
int A[aSize+1]={0, 221,411,345,926,451,1425,882, 1213,453,782};
int B[bSize+1]={0,45,664,1121,551,144,489,841,1120,356,1245};
int *a;
int *b;
int tempsubA[aSize+1]={0};
int tempsubB[bSize+1]={0};

int resultsubA[aSize+1]={0};
int resultsubB[bSize+1]={0};

void BacktrackSumA(int i);    //回溯遍历法
void BacktrackSumB(int i);

//快速排序的patition,Ds为降序
int patitionDs( int arr[],int left , int right )
{
int pivot=arr[left];
while(left<right)
{
while(left<right&&arr[right]<=pivot)
right--;
arr[left]=arr[right];
while(left<right&&arr[left]>=pivot)
left++;
arr[right]=arr[left];
}
arr[left]=pivot;
return left;
}
//快速排序,降序
void quickSortDs( int arr[], int left, int right )
{
int pivot;
if(left<right)
{
pivot=patitionDs( arr,left,right);
quickSortDs( arr, left, pivot-1);
quickSortDs(arr, pivot+1,right);
}
}

int patitionAs( int arr[],int left , int right )
{
int pivot=arr[left];
while(left<right)
{
while(left<right&&arr[right]>=pivot)
right--;
arr[left]=arr[right];
while(left<right&&arr[left]<=pivot)
left++;
arr[right]=arr[left];
}
arr[left]=pivot;
return left;
}

void quickSortAs( int arr[], int left, int right )
{
int pivot;
if(left<right)
{
pivot=patitionAs( arr,left,right);
quickSortAs( arr, left, pivot-1);
quickSortAs(arr, pivot+1,right);
}
}

//获取A序列的和。
void getSumA()
{
for(int i=1;i<=aSize;i++)
sumA=rSumA+=A[i];
}

void getSumB()
{
for(int i=1;i<=bSize;i++)
sumB=rSumB+=B[i];
}

//回溯法遍历A的解空间
void BacktrackSumA(int i)
{
if(i>aSize)
{
   if(cSumA>comSum && cSumA<=sumB)
{
   rSumB=sumB;
BacktrackSumB(1);
int f=0;
}
return;
}
if(cSumA+rSumA>comSum)
{
rSumA-=a[i];

cSumA+=a[i];
tempsubA[i]=a[i];
BacktrackSumA(i+1);        //系数xi取1
tempsubA[i]=0;
cSumA-=a[i];

BacktrackSumA(i+1);        //系数xi取0

rSumA+=a[i];
}
}

void BacktrackSumB( int i)
{
if(i>bSize)
return;
if(cSumB+rSumB>=cSumA)
{
rSumB-=b[i];
if(cSumB+b[i]==cSumA)
{
for(int j=0;j<=aSize;j++)
resultsubA[j]=tempsubA[j];
for(int j=0;j<bSize;j++)
resultsubB[j]=tempsubB[j];
resultsubB[i]=b[i];
comSum=cSumA;
return;
}
if(cSumB+b[i]<cSumA)    //系数yi取1
{
cSumB+=b[i];
tempsubB[i]=b[i];
BacktrackSumB(i+1);
cSumB-=b[i];
tempsubB[i]=0;
}
BacktrackSumB(i+1);     //系数yi取0
rSumB+=b[i];
}
}

int _tmain(int argc, _TCHAR* argv[])
{
getSumA();
getSumB();
if(sumA<sumB)
{
a=A;
b=B;
}
else
{
int tem=sumA;
sumA=rSumA=sumB;
sumB=rSumB=tem;
a=B;
b=A;
}
if(sumB-sumA>VALUE)        //用VALUE做阀值,以确定用哪种排序
{
quickSortAs( a, 1,aSize);
quickSortAs( b, 1,bSize);
}
else
{
quickSortDs( a, 1,aSize);
quickSortDs( b, 1,bSize);
}
BacktrackSumA(1);
cout<<comSum;

getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: