0-1背包的递归与非递归实现
1/*0-1背包递归*/
2#include<iostream> 2 #include <iomanip> 3 using namespace std; 4 5 int w[]={1,3,4,5};//物品重量数组 6 int v[]={2,30,44,20};//物品价值数组 7 int contain=5;//背包容量 8 int y[4]={-1,-1,-1,-1};//解向量,y[i]=1表示选取物品,y[i]=0表示不选取物品 9 10 int f(int n,int contain) 11 { 12 if(n==0 || contain==0){//当物品数量为0,或者背包容量为0时,最优解为0 13 return 0; 14 } 15 else 16 { 17 //从当前所剩物品的最后一个物品开始向前,逐个判断是否要添加到背包中 18 for(int i=n-1;i>=0;i--){ 19 //如果当前要判断的物品重量大于背包当前所剩的容量,那么就不选择这个物 20 //在这种情况的最优解为f(n-1,C) 21 if(w[i]>contain){ 22 y[i]=0; 23 return f(n-1,contain); 24 } 25 else 26 { 27 //如果当前待判断的物品重量wi<C,那么就选取f(n-1,C)和vi+f(n-1,C-wi)中的最大值 28 int tmp1=f(n-1,contain);//不选择物品i的情况下的最优解 29 int tmp2=v[i]+f(n-1,contain-w[i]);//选择物品i的情况下的最优解 30 //返回选择物品i和不选择物品i中最优解大的一个 31 if(tmp1>tmp2){ 32 y[i]=0;//这种情况下表示物品i未被选取 33 return tmp1; 34 } 35 else 36 { 37 y[i]=1;//物品i被选取 38 return tmp2; 39 } 40 } 41 } 42 } 43 } 44 int main() 45 { 46 int maxvalue=f(4,5); 47 for(int i=0;i<4;i++){ 48 if(y[i]==1) 49 { 50 cout<<"Object"<<i+1<<"is selected"<<"It's value is"<<setw(2)<< 51 v[i]<<"It's Weight is"<<setw(2)<<w[i]<<endl; 52 } 53 } 54 cout<<"Maximum Value is"<<maxvalue<<endl; 55 return 0; 56 57 }
1 /* 0-1背包非递归*/ 2 #include "stdio.h" 3 #define N 100 4 5 int main() 6 { 7 void Knapsack(int [],int [],int ,int ,int [][1000]); 8 void Traceback(int [],int [],int ,int ,int [][1000],int []); 9 int n,i,c,v[N+1],w[N+1],m[N+1][1000],x[N+1]; 10 //v[]:价值,w[]:重量,c:背包可容纳重量,n:物品件数 11 //m[][]:存放最大总价值的数组 12 //m[i][j]表示背包容量为j,可选择物品为i,i+1,...,n时0-1背包问题的最优值 13 //x[i]表示是否放入第i件物品,1为是,0为否 14 printf("input n:"); 15 scanf("%d",&n); 16 printf("input c:"); 17 scanf("%d",&c); 18 printf("input v:"); 19 for(i=1;i<=n;i++) scanf("%d",&v[i]); 20 printf("input w:"); 21 for(i=1;i<=n;i++) scanf("%d",&w[i]); 22 Knapsack(v,w,c,n,m); 23 Traceback(v,w,c,n,m,x); 24 printf("answer:%d\n",m[1][c]); 25 for(i=1;i<=n;i++) 26 if(x[i]) printf("%d ",i); 27 printf("\n"); 28 29 return 0; 30 } 31 32 void Knapsack(int v[],int w[],int c,int n,int m[][1000]) 33 //v[]:价值,w[]:重量,c:背包可容纳重量,n:物品件数 34 //m[][]:存放最大总价值的数组 35 //m[i][j]表示背包容量为j,可选择物品为i,i+1,...,n时0-1背包问题的最优值 36 { 37 int i,j,t; 38 int jMax; 39 jMax=w[n]-1<=c? w[n]-1:c; 40 //jMax是使m[n][x]为0的x最后下标 41 for(j=0;j<=jMax;j++) m[n][j]=0; 42 //对于背包容量k(0<=k<=jMax),物品n是超重的,故在这些容量下,一定不会选择物品n 43 //故(m[n][0],m[n][1],...m[n][jMax-1],m[n][jMax]) = 0 44 for(j=w[n];j<=c;j++) m[n][j]=v[n]; 45 //对于背包容量k(w[n]<=k<=c),物品n是可容纳的,故在这些容量下,选择物品n 46 //以下是前面两个for循环的实例: 47 //例1:n=6,w[6]=9,c=12,则(m[6][0],m[6][1],m[6][2],...m[6][7],m[6][8])=0 48 // (m[6][9],...m[6][12]=v[6] 49 //例2:n=6,w[6]=9,c=8,则(m[6][0],m[6][1],m[6][2],...m[6][8],m[6][9])=0 50 51 //到此为止,已经求出可选择物品只有第n件时在重量k(0<=k<=c)情况下的最优值 52 //接下来求可选择物品为(第n-1件、第n件),(第n-2件、第n-1件、第n件),...,(第2件、第3件...第n件) 在重量k(0<=k<=c)情况下的最优值 53 for(i=n-1;i>1;i--) 54 { 55 jMax=w[i]-1<=c? w[i]-1:c; 56 //jMax是使m[i][x]为0的x最后下标 57 for(j=1;j<=jMax;j++) m[i][j]=m[i+1][j]; 58 //对于背包容量k(0<=k<=jMax),物品i是超重的,在这些容量下,一定不会选择物品i 59 //即(m[i][1]=m[i+1][1],m[i][2]=m[i+1][2],...,m[i][jMax]=m[i+1][jMax]; 60 for(j=w[i];j<=c;j++) 61 { 62 //对于背包容量k(w[i]<=k<=c),物品i是可容纳的,但是否一定选择物品i? 63 t=w[i]; 64 m[i][j]=m[i+1][j]>=m[i+1][j-t]+v[i]?m[i+1][j]:m[i+1][j-t]+v[i]; 65 //以上语句你能看明白,这是0-1背包模型的关键 66 } 67 //到此为止,已经求出可选择物品为(第n-1件、第n件),(第 n-2件、第n-1件、第 n件),...,(第 2件、第 3件...第 n 件) 在重量 k(0<=k<=c)情况下的最优值 68 //接下来是求可选择物品为(第 1件、第 2件...第 n件) 在重量 k(0<=k<=c)情况下的最优值吗? 69 //No!只需求可选择物品为(第 1件、第 2件...第 n件) 在重量 c(真正的背包容量)下的最优值 70 m[1][c]=m[2][c]; //假设不放入第一件物品 71 t=w[1]; 72 if(w[1]<=c) m[1][c]=m[1][c]>=m[2][c-t]+v[1]?m[1][c]:m[2][c-t]+v[1]; 73 //可以容纳第一件物品的情况下,该如何选择? 74 } 75 } 76 77 void Traceback(int v[],int w[],int c,int n,int m[][1000],int x[]) 78 { 79 //v[]:价值,w[]:重量,c:背包可容纳重量,n:物品件数 80 //m[][]:存放最大总价值的数组 81 //m[i][j]表示背包容量为j,可选择物品为i,i+1,...,n时0-1背包问题的最优值 82 //x[i]表示是否放入第i件物品,1为是,0为否 83 int i; 84 for(i=1;i<n;i++) 85 if(m[i][c]==m[i+1][c]) x[i]=0; 86 //可选择物品中有第i件物品或没有第i件物品,最优值都是一样的,故一定没有放入第 i件物品 87 else 88 { 89 x[i]=1; 90 c=c-w[i]; 91 //这个语句很重要,为判断是否选择了第 i+1件物品做准备 92 } 93 if(m[n][c]>0) //单独判断是否选择了第 n件物品 94 x[i]=1; 95 else x[i]=0; 96 }