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 }

 

posted @ 2014-03-10 23:45  拦云  阅读(2506)  评论(0编辑  收藏  举报