1 背包问题 (二维暴力做法)
实质 递归问题:
思想:
f[i][j]表示只看前i个物品,总体积为j的情况下,总价值最大为多少
result:max{f[n][0~V]}
递归链条:
f[i][j]的求法:
( 假设已经把i-1个物品的状态已经计算完 现求的 i 个的状态 )
1. 不选第 i 个物品:f [ i ][ j ]=f [ i-1][ j ]; //只看前i-1个物品 体积为 j 时的最大价值
2. 选第 i 个物品:f [ i ][ j ]=f [ i-1 ][ j-v[i] ]+w[ i ]; //若选了i,则前i-1个物品所能用的体积为j-v[i];
则最终结果为f[i][j]=max[1.,2.];
递归初始化:
f[0][0]=0; --在任何物品都未选时,体积为0 最大价值为0;
代码实现:
#include<bits/stdc++.h>
using namespace std;
int m,n,i,j;
int f[1010][1010];
int v[1010],w[1010];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])
{
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
}
int ans=0;
for(int i=0;i<=m;i++)ans=max(ans,f[n][i]);
//前n个物品 即所有物品 体积为 i 时可达的最大价值
printf("%d",ans);
return 0;
}
2 背包问题 一维数组简化:
优化后程序占用空间减少:
代码实现:
#include<bits/stdc++.h>
using namespace std;
int m,n,i,j;
int f[1010];
int v[1010],w[1010];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=v[i];j--) 改成倒序的原因:f[j] 是i-1的时候更新的 如果正序的话
在i循环里遍历到 j 之前就已经遍历 j-v[i] ( j-v[i] < j )这样比较的就是 i 层的 而非 原代码
i-1 层的
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
printf("%d",f[m]); f[m]表示的不止是体积为m时的最大价值,还表示所有小于m的体积中的最大价值
当 i = 1 时 所有大于 v[1] 的 f[j] 全部被赋值为 w [1] 包括 f[m]
当 i = 2 时 若 j (m) - v[2] > v[1] 则要在 原本的 f [m-v[2]] 的初始化为 w[1] 的基础上 加上w[2] 如果不能加 则 f[m]的前半部分空着 由于倒序 f[m] 从后边填起;前面可为空;
//则若最佳解是体积为k 则 j [ m ] 是由 j[m-k] (=0) 加上j[k]得到的 (因为是从前往后添加的)
若想得到刚好体积为m的解法 只需要 除j[0]外的所有 j 都初始化为负无穷 则相加时只有m-k=0时才能加出正的结果
return 0;
}