给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
0-1背包问题是一个特殊的整数规划问题。
1.最优子结构
证明:是下式的最优解:
解:
设不是最优解,则存在一个更优解,满足:
所以
与是下最优解矛盾
2.递推方程
m[i[[j]:表示背包容量为j,在前i种物品中选择。
3.最优值
#include <bits/stdc++.h>
using namespace std;
/*
函数功能:求0-1背包问题的最大价值
函数形参:物品数量和背包容量
函数返回值:返回最大值
*/
int fun(int n,int m,vector<int> w,vector<int> v,vector<vector<int> >& f)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<w[i])
f[i][j]=f[i-1][j];
else{
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
// cout<<"i="<<i<<"\tj="<<j<<endl;
// cout<<"f[i-1][j]="<<f[i-1][j]<<"\tf[i-1][j-w[i]]+v[i]="<<f[i-1][j-w[i]]+v[i]<<"\tf[i][j]="<<f[i][j]<<endl<<endl;
}
}
}
return f[n][m];
}
void traceback(int n,int c,vector<int> w,vector<vector<int> >& f,vector<int> &x)
{
for(int i=n;i>1;i--)
{
if(f[i][c]==f[i-1][c])
x[i]=0;
else
{
x[i]=1;
c-=w[i];
}
}
x[1]=(f[1][c]>0)?1:0;
}
int main()
{
int n=5, m=10;
vector<int> w{0,2,2,6,5,4},v{0,6,3,5,4,6};
vector<vector<int> > f(6, vector<int>(11));
cout<<fun(n,m, w,v,f)<<endl<<endl;
for(int i=1;i<=5;i++){
for(int j=1;j<=10;j++){
cout<<f[i][j]<<"\t";
}
cout<<endl;
}
cout<<endl;
cout<<"物品选择情况:"<<endl;
vector<int> x(n+1);
traceback(n,m,w,f,x);
for(int i=1;i<=n;i++)
cout<<x[i]<<"\t";
return 0;
}
m[i][j]
n=5;c=10; w={2,2,6,5,4},v={6,3,5,4,6}
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
2 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 11 | 11 | 14 |
4 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 10 | 11 | 13 | 14 |
5 | 0 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |