两个序列最大子集公共和问题
2012-05-07 23:36
417 查看
前几天听同学说起这样一个问题,说有两堆物品,分别从两堆物品中挑出一些物品,使这些物品重量之和相同,要求使重量之和最大。我把这个问题抽象出来后是这样子:有两个序列,从两个序列中各选出一些元素组成子序列,使这两个子序列的和相等,要求使子序列的和最大。
我设计的算法如下:
1.两个序列选择子序列按照0-1方式生成解空间。所以按回溯方式遍历解空间。
2.要实现高效得考虑贪心性。
3.序列和小的序列的和很大概率上就是两个序列的最大子集公共和。
4.序列和小的序列做基础。
5.对原序列排序,如果较密集,小序列用降序排列。如果两个序列和的差较大,大序列用升序排列。
我设计的算法如下:
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; }
相关文章推荐
- 最长公共子串、最长公共子序列、最长回文子串、模式匹配、最大子序列--字符串问题整理
- 求两个序列的最大公共子序列的长度(递归解法)
- LCS最大公共子序列问题
- LCS最大公共子序列问题
- 动态规划 字符串最大公共子序列以及最大公共子串问题LCS
- buct oj 最大公共子序列问题
- 一个看似简单却复杂的问题:求两个字符串的 左向右匹配 所有的 最长连续的 公共子字符串( 在每个字符串中先后次序相同的) 序列
- 递归小程序_求两个串的最大公共子序列的长度
- LCS最大公共子序列问题
- 动态规划3——最大公共子序列问题
- Common Subsequence 最大公共子序列问题
- 最长公共子串、最长公共子序列、最长回文子串、模式匹配、最大子序列--字符串问题整理
- java实现字符串匹配问题之求两个字符串的最大公共子串
- java 递归求求两个串的最大公共子序列的长度
- java实现字符串匹配问题之求两个字符串的最大公共子串
- 2015年阿里在线笔试题:求两个字符串的最大公共子序列长度的C语言解法
- 最大连续子序列和,乘积,最长递增子串,最长公共子串,子序列等问题(动态规划等)
- C语言 最长子序列问题(两个序列的公共子序列)
- 动态规划_最大公共子序列长度问题
- 两个字符串的最大公共子序列和最大公共子串