初始条件如下

0-1背包_回溯法_伪代码

看下面的动图了解回溯的过程

0-1背包_回溯法_c++_02

0-1背包_回溯法_伪代码_03

 

 对应的解空间和约束条件和状态树如下

0-1背包_回溯法_伪代码_04

设当前有N个物品,容量为M; 这些物品要么选,要么不选,我们假设选的第一个物品编号为i(1~i-1号物品不选),问题又可以转化为有N-I个物品(即第I+1~N号物品),容量为M-Wi的子问题……如此反复下去,然后在所有可行解中选一个效益最大的便可。

回溯(状态恢复)后,需恢复的状态有:

Bag[k] 背包可装的物品重量:wei:=wei+w[k]*i 已装物品的价值总和:count:=count-v[k]*i

参考伪代码如下

1 procedure work(k,wei:integer);
2 var i,j:integer;
3 for i:=1 downto 0 do
4 if (wei-w[k]*i>=0)
5 {
6 bag[k]:=i;
7 count:=count+v[k]*i;
8 if (k=n) and (count>best)
9 {best:=count;
10 for j:=1 to n do y[j]:=bag[j];
11 }
12 if k<n then work(k+1,wei-w[k]*i);
13 count:=count-c[k]*i; {状态恢复}
14 }

下面是详细的代码

1 #include<bits/stdc++.h>
2 using namespace std;
3 int v[10];//物品的价值
4 int bag[10];//记录解空间物品的状态1为装入0为没有装入
5 int w[10];//每个物品的重量
6 int y[10];//记录最佳装载的方案
7 int count1=0;//记录该装载方案的总价值
8 int best=0;//记录最佳装载方案的总价值
9 void procedure(int k,int wei,int N)
10 {
11
12 for(int i=0;i<=1;i++){//0为装入1位不装入
13 if(wei-w[k]*i>=0){//如果还有剩余空间,实现了剪枝
14 bag[k]=i;//记录该物品是否被装入
15 count1=count1+v[k]*i;//总价值
16 if(k==N && count1 >best){//此时装载方案是目前已知的装载方案最优
17 best=count1;//更新这个最优总价值
18 for(int j=1;j<=N;j++){//记录此时背包装入状态
19 y[j]=bag[j];
20 }
21 }
22 if(k<N){//k==n递归
23 procedure(k+1,wei-w[k]*i,N);
24 }
25
26 count1-=v[k]*i;//k<n回溯上一步
27 }
28 }
29 }
30 int main()
31 {
32 memset(v,0,sizeof(v));
33 memset(bag,0,sizeof(bag));
34 memset(y,0,sizeof(y));
35 memset(w,0,sizeof(w));
36 cout << "请输入物品的总个数(n<=9)" << endl;
37 int n;
38 cin >> n;
39 cout << "请输入每个物品的重量" << endl;
40 for(int i=1;i<=n;i++){
41 cin >> w[i];
42 }
43 cout << "请输入每个物品的价值" << endl;
44 for(int i=1;i<=n;i++){
45 cin >> v[i];
46 }
47 cout << "请输入该背包最多可以装入的物品的总重量" << endl;
48 int wei;
49 cin >> wei;
50 procedure(0,wei,n);
51 cout <<"该背包可以装入的最大物品总价值是" << endl;
52 cout << best << endl;
53 cout << "装入的物品有" << endl;
54 for(int i=1;i<=n;i++){
55 if(y[i]==1){
56 cout << "物品" << i << " ";
57 }
58 }
59 }

运行结果如下

0-1背包_回溯法_c++_05

 

作者:你的雷哥

本文版权归作者所有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。