一個集合x有都不相同的n個元素,使用這個集合中的不定個數的元素,組成一個和爲s的序列,求出所有符合的序列,元素可以重複使用,只要元素的個數相同不考慮順序。
比如集合是x={2,3,4,5,7}; n=5, s=12可以得出以下的序列:
2 2 2 2 2 2
2 2 2 3 3
3 3 3 3
2 2 2 2 4
2 3 3 4
2 2 4 4
4 4 4
2 2 3 5
3 4 5
2 5 5
2 3 7
5 7
解題思路:
元素存在arr數組中,大小爲size。
path[i][j]表示數組前i個元素(一個元素可出現多次),組成重量恰好爲j裝入揹包的可能,如可能則爲true,否則爲false。得到遞推關係:
path[i][j]=true,if path[i][j-arr[i]]=true的話;否則爲false。
邊界條件path[i][0]=true(i爲1...size),爲了避免遍歷,在程序中使用hashtable數組,如果可以通過前面的元素組成容量爲j的揹包,則hashtable[j]=true,否則爲false。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | |
1 | T | F | T | T | T | F | T | F | T | F | T | F | T |
2 | T | F | F | T | F | T | T | T | T | T | T | T | T |
3 | T | F | F | F | T | F | T | T | T | T | T | T | T |
4 | T | F | F | F | F | T | F | T | T | T | T | T | T |
5 | T | F | F | F | F | F | F | T | T | T | T | T | T |
求出path數組後,通過printPath(int i,int j,int c)函數打印出所有的路徑。printPath(int i,int j,int c)是個遞歸函數,表示打印出所有第i個元素和前i-1個元素組成容量爲j的揹包的路徑,函數遞歸過程中使用v隊列保存過程中的元素,其中c爲v隊列的大小。如printPath(2,12,0)將arr[2]=3加入隊列,然後調用printPath(2,9,1)將3入隊,然後分兩路,一路如藍字所示,調用printPath(1,6,2)將2入隊,...,隊列中元素爲3,3,2,2,2,逆序打印;一路如淺紅色所示,調用printPath(2,6,2)將3入隊,...,隊列中元素3,3,3,3,逆序打印。調用遞歸函數請讀者仔細體會。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <memory.h>
#define _DEBUG 1
#define MAXM 20
#define MAXN 10
int arr[MAXN];//數數組
bool path[MAXN][MAXM+1];//路線
bool hashtable[MAXM+1];//是否存在
int c;//記錄打印隊列大小
int v[MAXM+1];//打印隊列,數組大小最大爲MAXN+1,此時每個數爲1
void printPath(int i,int j,int c){
if(path[i][j] &&j-arr[i]==0){//第一個點
printf("%d ",arr[i]);
for(int t=c-1;t>0;t--){
printf("%d ",v[t]);
}
printf("%d\n",v[0]);
return;
}
assert(path[i][j]);
v[c++]=arr[i];//將元素加入到打印隊列中
for(int k=1;k<=i;k++){
if(path[k][j-arr[i]])
printPath(k,j-arr[i],c);
}
c--;//將元素從打印隊列中刪除
}
void solve(int size,int m){//size表示數組的大小,從1開始
int i,j;
//初始化
memset(path,false,sizeof(path));
hashtable[0]=true;
for(i=1;i<=size;i++){
for(j=arr[i];j<=m;j++){
if(hashtable[j-arr[i]]){
hashtable[j]=true;
path[i][j]=true;
}
}
}
for(i=1;i<=size;i++){
if(path[i][m]){
printPath(i,m,0);
}
}
}
int main(){
#if _DEBUG==1
freopen("interview.in","r",stdin);
freopen("interview.out","w",stdout);
#endif
int n,m;
int i,j;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&arr[i]);
}
solve(n,m);
return 0;
}