acwing算法基础课V
第五章 动态规划(一)
- 非常常见的dp的模型, 背包模型.
- 不同类型的dp 线性dp 计数dp 等....
一个物体 有 体积 \(v_i\) 和价值 \(w_i\) 用w表示权重的意思.
每件物品仅用一次.
总体积小于等于 \(V\) 目标是让总价值 \(W\) 最大, 最大是多少.
- 01背包. 每个物品最多只用一次.
- 完全背包 每件物品无限个
- 多重背包 n个. 优化问题.
- 分组背包. 每一组最多一个物品.
问背包可以装的下的情况下, 最多可以装多少物品.
闫式DP
-
状态表示
f(i,j)-
集合 所有选法: 前
i个物品中, 总体积 \(\le\)j -
属性 max / min / 数量.
存储的是所有选法的最大值.
-
-
状态计算
- 状态转移怎么来的?
- 集合划分. 不重 不漏.
- f(i,j) 不含
i和 含i
DP优化.
背包问题
01背包问题
f(i,j) = max(f(i-1,j), f(i-1,j-v[i])+w[i])
int v[N3], w[N3];
int f[N3][N3];
int main() {
int n = read(), m = read();
rep(i, 1, n + 1) v[i] = read(), w[i] = read();
rep(i, 1, n + 1) {
rep(j, 1, m + 1) {
f[i][j] = f[i - 1][j]; //第一个集合;
if (v[i] <= j)
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
cout << f[n][m] << endl;
return 0;
}
优化成一维 看变量什么时候发生的改变.
int v[N3], w[N3];
int f[N3]; // 可以优化掉一维的数量, 因为这里存储的还是不变量.
int main() {
int n = read(), m = read();
rep(i, 1, n + 1) v[i] = read(), w[i] = read();
rep(i, 1, n + 1) {
per(j, m + 1, v[i]) { // 注意 从后到前循环, 同时 最多循环到 v[i]
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
cout << f[m] << endl;
return 0;
}
用 rep 和 per的时候也挺开心的.
完全背包问题

int v[N3], w[N3], f[N3];
int main() {
int n = read(), m = read();
rep(i, 0, n)v[i] = read(), w[i] = read();
rep(i, 0, n) {
rep(j, v[i], m + 1) { //只要变化一下, 就能选择到很多了.
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
O(f[m]);
}
多重背包问题
具体的个数.
滑动窗口最大值, 单调队列优化? ???
int f[N3][N3], w[N3], v[N3], s[N3];
int main() {
int n = read(), m = read();
rep(i, 1, n + 1) v[i] = read(), w[i] = read(), s[i] = read();
rep(i, 1, n + 1) // O(n)
rep(j, 0, m + 1) // O(m)
for (int k = 0; k <= s[i] && k * v[i] <= j; k++)
f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]); //O(k)
// 第三重循环直接暴力检验一下.
O(f[n][m]);
}
多重背包问题II
二进制优化方式. 拆分.成01背包问题.
\(s->log(s)\) 的复杂度
const int N = 25000, M = 2010;
int n, m, cnt;
int v[N], w[N], f[M];
int main() {
n = read(), m = read();
rep(i, 0, n) {
int a = read(), b = read(), s = read();
int k = 1;
while (k <= s) {
s -= k, cnt++; // 每个物品进行拆分.
v[cnt] = a * k, w[cnt] = b * k; // 按照 cnt 进行放置.
k *= 2;
}
if (s) ++cnt, v[cnt] = a * s, w[cnt] = b * s;
}
n = cnt;
rep(i, 1, n + 1) {
per(j, m + 1, v[i])
f[j] = max(f[j], f[j - v[i]] + w[i]); // 简单的01背包问题.
}
O(f[m]);
}
分组背包问题
Q: N 和 V . 多组物品, 每组只能选一个. 体积 \(v_{ij}\) 价值 \(w_{ij}\) , 问背包最大价值?
分组直接 多次循环就好.
每组每个都取一遍 for(每个组) for(每个体积) for(每个物品) 所以是 \(O(n^3)\)的复杂度.
// 然后 组不同了再换是吗? 怎么优化到一维的呢?
const int N = N2;
int f[N], v[N][N], w[N][N], s[N];
int n, m;
int main() {
n = read(), m = read();
rep(i, 0, n) {
s[i] = read();
rep(j, 0, s[i]) v[i][j] = read(), w[i][j] = read();
}
rep(i, 0, n) {
per(j, m + 1, 0) {
rep(k, 0, s[i]) {
if (v[i][k] <= j)
f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
// 这个可以保证分组, 因为可以保证前面的不被覆盖..
}
}
}
O(f[m]);
return 0;
}

浙公网安备 33010602011771号