完全背包问题
题意
- 选取的物品无限
- 求价值最大值
分析图解
难点:状态计算——第i个物品选(0 - k)个。那么k*v【i】 <= 背包剩余空间
- 第i个物品,选k个
- 那么需要加上 k个物品的价值
朴素的算法
/*
f[i - 1][j] 一个都不选 k == 0
f[i - 1][j - v[i] * k] + w[i] * k 选1 ~ k个 1 <= k <= s[i]
*/
#include <iostream>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N][N];
int main ()
{
int n, m;
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 = 1 ; j <= m ; j ++ )
for(int k = 0 ; k * v[i] <= j ; k ++ )/有k个可以选
f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
cout << f[n][m] << endl;
return 0;
}
优化图解
优化后的代码
#include <iostream>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N][N];
int main ()
{
int n, m;
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 = 1 ; j <= m ; j ++ )
{
f[i][j] = f[i - 1][j];//如果不选i,那么必须从前一项继承下来
if(j >= v[i]) f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
}
cout << f[n][m] << endl;
return 0;
}
优化状态转移方程 + 降维优化
#include <iostream>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N];
int main ()
{
int n, m;
cin >> n >> m;
for(int i = 1 ; i <= n ; i ++ ) cin >> v[i] >> w[i];
for(int i = 1 ; i <= n ; i ++ )
// //因为此时,状态和同层的 i 相关,那么如果状态压缩,那么可以从小到大循环
for(int j = v[i] ; j <= m ; j ++ )
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
cout << f[m] << endl;
return 0;
}