0-1 背包问题
N件物品 背包最大重量W,
每个物品都有value和w
每个物品都只能取一次,
重量不超过W的情况下
求价值最大。
0<N,W<1000
0<wi,valuei<1000
输入:
N W
N行:重量和价值
wi valuei
示例:
4 5
1 2
2 4
3 4
4 5
8
思路:
先用表格即二维数组的想法规划一下,将没种情况都列举出来,最后找到最大值即可。
f[i][j] 表示在j的重量下此时,只考虑前i个物品的最大价值
此时俩种情况:
1.不算i物品,此时f[i][j] = f[i-1][j];即上一行时(不包括第i个物品的最大价值)
2.计算i物品:f[i][j] = f[i-1][j-w[i]]+value[i];
即:将减去i物品的重量时的最大价值+ i物品的价值
将两种情况对比,取最大的值赋给f[i][j]
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int const N = 1010;
int f[N][N]; // f[i][j] i代表物品,j代表重量,表示在j重量下i个物品所能达到的最大价值
int m,n;
int main()
{
int w[N],value[N];
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i]>>value[i];
for(int i = 1;i<=n;i++)
{
for(int j =0;j<=m;j++)
{
f[i][j] = f[i-1][j];
if(j>=w[i]) // 如果j质量小于i的质量说明放不进去所以必须>=才考虑俩种情况
{
f[i][j] = max(f[i][j],f[i-1][j-w[i]]+value[i]);
}
}
}
int res =0;
for(int i =1;i<=n;i++) res= max(res,f[i][m]);
cout<<res<<endl;
}
此时算法的时间复杂度为O(n2),一般测试平台每秒运行107次或者108
优化算法:
将二维数组变为一维数组
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int const N = 1010;
int f[N]; // f[i] 表示在i重量下个物品所能达到的最大价值
int m,n;
int main()
{
int w[N],value[N];
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i]>>value[i];
for(int i = 1;i<=n;i++) // 外层循环代表i个物体,时候在j重量下的最大价值
{
for(int j =m;j>=w[i];j--) // 这个时候没有i-1层所以要从大到小排序
{
f[j]=max(f[j],f[j-w[i]]+value[i]);
}
}
int res =f[m];
cout<<res<<endl;
}
完全背包问题
跟0-1背包不同,此时物体i可以取无限次
/*
f[i] 表示总重量为i的情况下,最大价值多少
在0-1背包问题下,从大到小排表示在没有取i的情况下,此时的最大价值就是上一个物品的最大价值,即i取0次
for(int i =1;i<=n;i++)
for(int j =m;j>=v[i];j--)
f[j]= max(f[j],f[j-v[i]]);
因此完全背包问题只需要将排序改变就变成了取无数次后的结果,因为这就是取反的效果
result = max(f[0.....m])
for(int i =1;i<=n;i++)
for(int j =v[i]; j<=m;j++)
f[j]= max(f[j],f[j-w[i]]+value[i]);
*/
此时代码为:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int N= 1010;
int f[N];
int m,n;
int w[N],value[N];
int main()
{
cin>>n>>m;
for(int i =1;i<=n;i++)
cin>>w[i]>>value[i];
for(int i =1 ;i<=n;i++)
{
for(int j =w[i];j<=m;j++)
f[j] = max(f[j],f[j-w[i]]+value[i]);
}
cout<<f[m]<<endl;
}