总结:
如果用的是上一层状态, 就从大到小枚举。
如果用的是本层状态, 就从小到大枚举。
- 对于01背包:要验证当前第i个物品是否拿还是不拿,必须依赖上一轮(i-1)轮的状态,这个状态是绝对不会出现已经拿取了第i个物品的情况。
所以f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i] + w[i]])
- 但是在完全背包中,由于物品有多个,可能要验证当前是否拿 k个第i个物品,依赖的应该是 k - 1个第i个物品(不知道我说的对不对emm)
所以f[i][j] = max(f[i - 1][j], f[i][j - v[i] * k] + w[i] * k)
关于01背包和完全背包
区别 | 状态方程 | 循环 |
---|---|---|
01背包 | f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i] + w[i]]) |
for (int j = m; j >= v[i]; j -- ) |
完全背包 | f[i][j] = max(f[i - 1][j], f[ i ][j - v[i]] + w[i]) |
for (int j = v[i]; j <= m ; j ++ ) |
优化成一维做法:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N];
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 = v[i]; j <= m; j ++ )
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
cout << f[m] << endl;
return 0;
}
优化做法:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
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 = 1; j <= m; j ++ )
{
if (j < v[i])
f[i][j] = f[i - 1][j];
else
f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
}
cout << f[n][m] << endl;
return 0;
}
朴素做法:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
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 = 1; j <= m; j ++ )
for (int k = 0; k * v[i] <= j; k ++ )
f[i][j] = max(f[i - 1][j], f[i - 1][j - k * v[i]] + k * w[i]);
cout << f[n][m] << endl;
return 0;
}
萌新自己的理解,如果有误欢迎您指正~并表示感谢!