问题
01背包问题之前用动态规划的方法实现过:动态规划 01背包问题(简单易懂)
01背包问题一般用回溯法的子集树框架来实现
#include<iostream>
using namespace std;
int n,c,bestp;//物品个数,背包容量,最大价值
int p[10000],w[10000],x[10000],bestx[10000];//物品的价值,物品的重量,物品的选中情况
//cp当前已放入的总价值,cw当前已放入的总重量
void backtrack(int i,int cp,int cw)
{
if(i>n)
{
if(cp>bestp)
{
bestp=cp;
for(i=1;i<=n;i++) bestx[i]=x[i];
}
}
else
{
//每一层的物品都可以选择放入或者不放,0表示不放,1表示放入
for(int j=0;j<=1;j++)
{
x[i]=j;
if(cw+x[i]*w[i]<=c)
{
cw+=w[i]*x[i];
cp+=p[i]*x[i];
backtrack(i+1,cp,cw);
cw-=w[i]*x[i];
cp-=p[i]*x[i];
}
}
}
}
int main()
{
bestp=0;
cin>>n>>c;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=n;i++) cin>>p[i];
backtrack(1,0,0);
cout<<bestp<<endl;
for(int i=1;i<=n;i++) cout << bestx[i] << " ";
}
输入:
3 10
5 5 3
40 30 10
输出:
70
1 1 0
流程分析:
假如用一个数组来表示每一次递归,各个物品的选择情况,则:(0表示不选,1表示选)
(0,0,0) 全都不选 bestp = 0
(0,0,1) 选择第3个物品 bestp = 10
(0,1,0) ….
(0,1,1) ….
(1,0,0) ….
(1,0,1) ….
(1,1,0) 选择第1和第2 ,重量为10,bestp=70
(1,1,1) 全部选择,重量为13,剪去
当然也可以用排列树来实现
#include<iostream>
using namespace std;
int n, c, bestp=0, cw=0, cp=0; //物品个数,背包容量,最大价值,当前已选重量,当前已选价值
int w[10], v[10], x[10], bestx[10];//物品的价值,物品的重量,物品的选中情况
int vis[10];//记录是否已经选择
int tol = 0;//记录递归的次数
void back(int cur){
tol++;
if(cur > n){
if(cp > bestp){
bestp = cp;
for(int i=1; i<=n; i++){
bestx[i] = x[i];
}
}
}else{
for(int i=1; i<=n; i++){
if(!vis[i] && cw+w[i] <= c){
vis[i] = 1;
cw += w[i];
x[cur] = w[i];
cp += v[i];
back(cur+1);
//复位
cw -= w[i];
cp -= v[i];
x[cur] = 0;
vis[i] = 0;
}
if(cw+w[i] > c){
back(cur+1);
}
}
}
}
int main(){
cin >> n >> c;
for(int i = 1; i <= n; i++){
cin >> w[i];
}
for(int i = 1; i <= n; i++){
cin >> v[i];
}
back(1);
cout << bestp << endl;
for(int i = 1; i <= n; i++){
cout << bestx[i] << " ";
}
cout << endl << tol;
}
输入:
3 10
5 5 3
40 30 10
输出:
70
5 5 0