1 // 动态规划法解决0-1背包问题
2 //example:
3 //物品种类n=5,背包容量c=10,
4 //物品的重量向量 w={2,2,6,5,4},物品的价值向量 v={6,3,5,4,6}
5 // O(min{n*c,2^n})
6 #include "stdafx.h"
7 #include <cstdlib>
8 #include <iostream>
9
10 using namespace std;
11 template<class Type>
12 Type Knapsack(int n,Type c,Type v[],Type w[],Type**p,int x[])
13 {
14 int* head=new int[n+2];
15 head[n+1]=0;p[0][0]=0;p[0][1]=0;
16 int left=0,right=0,next=1;
17 head[n]=1;
18 for(int i=n;i>=1;i--){
19 int k=left;
20 for(int j=left;j<=right;j++){
21 if(p[j][0]+w[i]>c) break;
22 Type y=p[j][0]+w[i],m=p[j][1]+v[i];
23 while(k<=right&&p[k][0]<y){
24 p[next][0]=p[k][0];
25 p[next++][1]=p[k++][1];
26 }
27 if(k<=right&&p[k][0]==y){
28 if(m<p[k][1]) m=p[k][1];
29 k++;
30 }
31 if(m>p[next-1][1]) {p[next][0]=y;p[next++][1]=m;}
32 while(k<=right&&p[k][1]<=p[next-1][1]) k++;
33
34 }
35 while(k<=right){p[next][0]=p[k][0];p[next++][1]=p[k++][1]; }
36 left=right+1;right=next-1;head[i-1]=next;
37 }
38 Traceback(n,w,v,p,head,x);
39 return p[next-1][1];
40
41 }
42
43 template<class Type>
44 void Traceback(int n,Type w[],Type v[],Type**p,int* head,int x[]){
45 std::cout<<"物品清单如下:(‘0’表示没有,‘1’表示有)"<<endl;
46 Type j=p[head[0]-1][0],m=p[head[0]-1][1];
47 for(int i=1;i<=n;i++)
48 {
49 x[i]=0;
50 for(int k=head[i+1];k<=head[i]-1;k++){
51 if(p[k][0]+w[i]==j&&p[k][1]+v[i]==m){
52 x[i]=1;j=p[k][0];m=p[k][1];break;
53 }
54 }
55
56 std::cout<<"第"<<i<<"中物品的状态为:";
57 std::cout<<x[i]<<endl;
58 }
59
60 }
61
62
63
64 int main(int argc, char *argv[])
65 {
66
67 int w[]={10002,2,2,6,5,4},v[]={1,6,3,5,4,6}; //w和v的首零元素不计入0-1背包问题求解中
68 //int w[]={1002,4,5,6,2,2},v[]={8,6,4,5,3,6};
69 //cout<<w[3]<<v[3]<<endl;
70 int n=5,c=10;
71 int x[6]={0};
72 int** p=new int*[n+100];//数组必须足够大,next可能远大于n
73 for(int i=0;i<=n+100;i++) p[i]=new int[2];
74 cout<<"最优背包的解为:"<<endl;
75 int y=Knapsack(n,c,v,w,p,x);
76
77 cout<<"最大价值:"<<y<<endl;
78
79 return 0;
80 }