【ZJSU - 大红大紫:ACM - Template】比赛用模板08(W):动态规划
作者:互联网
动态规划
\(\tt{}0/1\) 背包
\(N\) 件物品中选取,使得选取物品总体积不超过 \(M\) 的前提下,使得物品的价值总和最大。每种物品一件, \(\mathcal{O}(N*M)\) 。
int n, m, dp[N]; int v[N], w[N];
void Zero_bag() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i];
for (int i = 1; i <= n; ++ i)
for(j = m; j >= v[i]; -- j)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
完全背包
每种物品无限, \(\mathcal{O}(N*M)\) 。
int n, m, dp[N]; int v[N], w[N];
void Cp_bag() {
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)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
多重背包
每种物品数量给定。
- 未优化版,\(\mathcal{O}(N*M*S)\) ,其中 \(S\) 为数量。
int n, m, dp[N][N]; int v[N], w[N], s[N];
void Multi_bag() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
for (int i = 1; i <= n; ++ i)
for (int j = 0; j <= m; ++ j)
for (int k = 0; k <= s[i] && k * v[i] <= j; ++ k)
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
}
- 使用二进制优化,\(\mathcal{O}(N*M*logS)\) ,其中 \(S\) 为数量。
int n, m, dp[N]; int cnt, v[N], w[N];
void Multi_bag() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
int vv, ww, ss; cin >> vv >> ww >> ss; // vv体积,ww价值,ss为数量,均临时储存
for (int k = 1; k <= ss; ss -= k, k *= 2) {
v[++ cnt] = vv * k;
w[cnt] = ww * k;
}
v[++ cnt] = vv * ss;
w[cnt] = ww * ss;
}
n = cnt;
for (int i = 1; i <= n; ++ i)
for (int j = m; j >= v[i]; -- j)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
- 使用单调队列优化, \(\mathcal{O}(N*M)\) 。
//使用单调队列优化
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int n, m, dp[N], V[N], W[N], C[N], q[N];
int clac (int i, int u, int k) { return dp[u + k * V[i]] - k * W[i]; }
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> n >> m;
memset(dp, 0xcf, sizeof dp);
dp[0] = 0;
for (int i = 1; i <= n; ++ i) {
cin >> V[i] >> W[i] >> C[i];
for (int u = 0; u < V[i]; ++ u) {
int l = 1, r = 0;
int maxp = (m - u) / V[i];
for (int k = maxp - 1; k >= max(maxp - C[i], 0); -- k) {
while (l <= r && clac(i, u, q[r]) <= clac(i, u, k)) -- r;
q[++ r] = k;
}
for (int p = maxp; p >= 0; -- p) {
while (l <= r && q[l] > p - 1) ++ l;
if (l <= r)
dp[u + p * V[i]] = max(dp[u + p * V[i]], clac(i, u, q[l]) + p * W[i]);
if (p - C[i] - 1 >= 0) {
while (l <= r && clac(i, u, q[r]) <= clac(i, u, p - C[i] - 1)) -- r;
q[++ r] = p - C[i] - 1;
}
}
}
}
int ans = 0;
for (int i = 1; i <= m; ++ i) ans = max(ans, dp[i]);
cout << ans << endl;
return 0;
}
分组背包:
给出分组情况,每组至多取一件物品。\(\mathcal{O}(N*M*S)\) 。
int n, m, dp[N]; int v[N][N], w[N][N], s[N];
void Group_bag() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
cin >> s[i];
for (int j = 1; j <= s[i]; ++ j) cin >> v[i][j] >> w[i][j];
}
for (int i = 1; i <= n; ++ i)
for (int j = m; j >= 0; -- j)
for (int k = 1; k <= s[i]; ++ k)
if (v[i][k] <= j) dp[j] = max(dp[j], dp[j - v[i][k]] + w[i][k]);
}
标签:int,大红大紫,08,ZJSU,cin,--,mathcal,void,dp 来源: https://www.cnblogs.com/WIDA/p/16676292.html