题目
算法标签: 动态规划, 线性 d p dp dp, 背包问题, 背包问题优化
思路
很明显的混合背包问题, 可以首先将完全背包问题转化为多重背包问题, 然后在多重背包问题基础上进行优化, 多重背包可以使用二进制拆分优化或者单调队列优化, 同时因为当前状态只与上一层状态有关, 可以使用滚动数组优化省掉一维空间
二进制优化代码
注意因为新拆分的物品数量要乘 log P \log P logP, 否则空间不够
拆分物品时间复杂度 O ( n log P ) O(n \log P) O(nlogP), 01 01 01背包时间复杂度 O ( n log P ) × M O(n \log P) \times M O(nlogP)×M, 总的时间复杂度就是 O ( n log P × M ) O(n \log P \times M) O(nlogP×M)
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 10010, M = 1010, K = 8;
int n, m;
int v[N * K], w[N * K], cnt;
int f[M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
char ch;
int a, b, c, d;
cin >> a >> ch >> b >> c >> ch >> d;
m = 60 * (c - a) + d - b;
cin >> n;
for (int i = 1; i <= n; ++i) {
int _v, _w, s;
cin >> _v >> _w >> s;
if (s == 0) s = m / _v;
int k = 1;
while (k <= s) {
cnt++;
v[cnt] = k * _v;
w[cnt] = k * _w;
s -= k;
k <<= 1;
}
if (s > 0) {
++cnt;
v[cnt] = s * _v;
w[cnt] = s * _w;
}
}
for (int i = 1; i <= cnt; ++i) {
for (int j = m; j >= v[i]; --j) {
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
cout << f[m] << "\n";
return 0;
}
单调队列优化代码
单调队列优化, 算法时间复杂度 O ( N M ) O(NM) O(NM)
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 10010, M = 1010;
int n, m;
int v[N], w[N], s[N];
int f[M], g[M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
char ch;
int a, b, c, d;
cin >> a >> ch >> b >> c >> ch >> d;
m = (c - a) * 60 + d - b;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> v[i] >> w[i] >> s[i];
if (s[i] == 0) s[i] = m / v[i];
}
int q[M];
for (int i = 1; i <= n; ++i) {
memcpy(g, f, sizeof f);
for (int r = 0; r < v[i]; ++r) {
int h = 0, t = -1;
for (int j = r; j <= m; j += v[i]) {
while (h <= t && j - q[h] > s[i] * v[i]) h++;
while (h <= t && g[j] >= g[q[t]] + (j - q[t]) / v[i] * w[i]) t--;
q[++t] = j;
f[j] = g[q[h]] + (j - q[h]) / v[i] * w[i];
}
}
}
cout << f[m] << "\n";
return 0;
}

京公网安备 11010502036488号