多重背包、混合背包
一共有n种货物, 背包容量为 t
每种货物的价值(v[i])、重量(w[i])、数量(c[i])都给出
请返回选择货物不超过背包容量的情况下,能得到的最大的价值
多重背包不进行枚举优化
| #include <iostream> |
| #include <vector> |
| |
| using namespace std; |
| |
| |
| int main() { |
| int n, w; |
| cin >> n >> w; |
| vector<int> cost(n + 1); |
| vector<int> value(n + 1); |
| vector<int> cnt(n + 1); |
| for (int i = 1; i <= n; ++i) |
| cin >> value[i] >> cost[i] >> cnt[i]; |
| |
| |
| vector<vector<int>> dp(n + 1, vector<int>(w + 1)); |
| |
| fill(dp[0].begin(), dp[0].end(), 0); |
| for (int i = 1; i <= n; ++i) { |
| for (int j = 0; j <= w; ++j) { |
| |
| dp[i][j] = dp[i - 1][j]; |
| |
| for (int k = 1; k <= cnt[i] && j - k * cost[i] >= 0; k++) |
| dp[i][j] = max(dp[i][j], dp[i - 1][j - k * cost[i]] + k * value[i]); |
| } |
| } |
| cout << dp[n][w]; |
| } |
| #include <iostream> |
| #include <vector> |
| |
| using namespace std; |
| |
| |
| int main() { |
| int n, w; |
| cin >> n >> w; |
| vector<int> cost(n + 1); |
| vector<int> value(n + 1); |
| vector<int> cnt(n + 1); |
| for (int i = 1; i <= n; ++i) |
| cin >> value[i] >> cost[i] >> cnt[i]; |
| |
| |
| |
| vector<int> dp(w + 1, 0); |
| for (int i = 1; i <= n; ++i) { |
| for (int j = w; j >= 0; j--) { |
| |
| for (int k = 1; k <= cnt[i] && j - k * cost[i] >= 0; k++) |
| dp[j] = max(dp[j], dp[j - k * cost[i]] + k * value[i]); |
| } |
| } |
| cout << dp[w]; |
| } |
多重背包通过二进制分组转化成 01 背包(模版)
| #include <iostream> |
| #include <vector> |
| |
| using namespace std; |
| |
| |
| int main() { |
| |
| int n, w; |
| cin >> n >> w; |
| |
| int m = 0; |
| vector<int> value(1); |
| vector<int> cost(1); |
| for (int i = 1, _value, _cost, _cnt; i <= n; ++i) { |
| cin >> _value >> _cost >> _cnt; |
| |
| for (int k = 1; k <= _cnt; k <<= 1) { |
| value.emplace_back(k * _value); |
| cost.emplace_back(k * _cost); |
| _cnt -= k; |
| m++; |
| } |
| |
| if (_cnt > 0) { |
| value.emplace_back(_cnt * _value); |
| cost.emplace_back(_cnt * _cost); |
| m++; |
| } |
| } |
| |
| |
| vector<int> dp(w + 1, 0); |
| for (int i = 1; i <= m; ++i) |
| for (int j = w; j >= cost[i]; j--) |
| dp[j] = max(dp[j], dp[j - cost[i]] + value[i]); |
| cout << dp[w]; |
| } |
多重背包单调队列优化
| #include <iostream> |
| #include <vector> |
| #include <queue> |
| |
| using namespace std; |
| |
| |
| int getValue(vector<vector<int>> &dp, vector<int> &cost, vector<int> &value, int i, int j) { |
| return dp[i - 1][j] - (j / cost[i]) * value[i]; |
| } |
| |
| |
| int main() { |
| int n, w; |
| cin >> n >> w; |
| vector<int> cost(n + 1); |
| vector<int> value(n + 1); |
| vector<int> cnt(n + 1); |
| for (int i = 1; i <= n; ++i) |
| cin >> value[i] >> cost[i] >> cnt[i]; |
| |
| |
| vector<vector<int>> dp(n + 1, vector<int>(w + 1)); |
| |
| fill(dp[0].begin(), dp[0].end(), 0); |
| |
| deque<int> q; |
| for (int i = 1; i <= n; ++i) { |
| |
| for (int mod = 0; mod <= min(w, cost[i] - 1); mod++) { |
| q.clear(); |
| for (int j = mod; j <= w; j += cost[i]) { |
| |
| while (!q.empty() && getValue(dp, cost, value, i, q.back()) <= getValue(dp, cost, value, i, j)) |
| q.pop_back(); |
| q.emplace_back(j); |
| |
| if (q.front() == j - cost[i] * (cnt[i] + 1)) |
| q.pop_front(); |
| dp[i][j] = getValue(dp, cost, value, i, q.front()) + (j / cost[i]) * value[i]; |
| } |
| } |
| } |
| cout << dp[n][w]; |
| } |
| #include <iostream> |
| #include <vector> |
| #include <queue> |
| |
| using namespace std; |
| |
| |
| int getValue(vector<int> &dp, vector<int> &cost, vector<int> &value, int i, int j) { |
| return dp[j] - (j / cost[i]) * value[i]; |
| } |
| |
| |
| int main() { |
| int n, w; |
| cin >> n >> w; |
| vector<int> cost(n + 1); |
| vector<int> value(n + 1); |
| vector<int> cnt(n + 1); |
| for (int i = 1; i <= n; ++i) |
| cin >> value[i] >> cost[i] >> cnt[i]; |
| |
| |
| |
| vector<int> dp(w + 1, 0); |
| |
| deque<int> q; |
| for (int i = 1; i <= n; ++i) { |
| for (int mod = 0; mod <= min(w, cost[i] - 1); mod++) { |
| q.clear(); |
| |
| for (int j = w - mod, count = 1; j >= 0 && count <= cnt[i]; j -= cost[i], count++) { |
| while (!q.empty() && getValue(dp, cost, value, i, q.back()) <= getValue(dp, cost, value, i, j)) |
| q.pop_back(); |
| q.emplace_back(j); |
| } |
| for (int j = w - mod, enter = j - cost[i] * cnt[i]; j >= 0; j -= cost[i], enter -= cost[i]) { |
| |
| if (enter >= 0) { |
| while (!q.empty() |
| && getValue(dp, cost, value, i, q.back()) <= getValue(dp, cost, value, i, enter)) |
| q.pop_back(); |
| q.emplace_back(enter); |
| } |
| dp[j] = getValue(dp, cost, value, i, q.front()) + (j / cost[i]) * value[i]; |
| if (q.front() == j) q.pop_front(); |
| } |
| } |
| } |
| cout << dp[w]; |
| } |
| #include <iostream> |
| #include <vector> |
| |
| using namespace std; |
| |
| int main() { |
| string time1, time2; |
| cin >> time1 >> time2; |
| int h1 = stoi(time1.substr(0, time1.find(':'))); |
| int m1 = stoi(time1.substr(time1.find(':') + 1, time1.size())); |
| int h2 = stoi(time2.substr(0, time2.find(':'))); |
| int m2 = stoi(time2.substr(time2.find(':') + 1, time2.size())); |
| |
| int w = (h2 - h1) * 60 + (m2 - m1); |
| |
| |
| int n; |
| cin >> n; |
| |
| int m = 0; |
| vector<int> value(1); |
| vector<int> cost(1); |
| for (int i = 1, _value, _cost, _cnt; i <= n; ++i) { |
| cin >> _cost >> _value >> _cnt; |
| |
| if (_cnt == 0) _cnt = w; |
| |
| for (int k = 1; k <= _cnt; k <<= 1) { |
| value.emplace_back(k * _value); |
| cost.emplace_back(k * _cost); |
| _cnt -= k; |
| m++; |
| } |
| |
| if (_cnt > 0) { |
| value.emplace_back(_cnt * _value); |
| cost.emplace_back(_cnt * _cost); |
| m++; |
| } |
| } |
| |
| |
| vector<int> dp(w + 1, 0); |
| for (int i = 1; i <= m; ++i) |
| for (int j = w; j >= cost[i]; j--) |
| dp[j] = max(dp[j], dp[j - cost[i]] + value[i]); |
| cout << dp[w]; |
| } |
混合背包 + 多重背包普通窗口优化
能成功找零的钱数种类
每一种货币都给定面值val[i],和拥有的数量cnt[i]
想知道目前拥有的货币,在钱数为1、2、3...m时
能找零成功的钱数有多少
也就是说当钱数的范围是1~m
返回这个范围上有多少可以找零成功的钱数
| #include <iostream> |
| |
| using namespace std; |
| |
| const int MAX_N = 101; |
| const int MAX_M = 100001; |
| |
| int n, m; |
| |
| int value[MAX_N]; |
| |
| int cnt[MAX_N]; |
| |
| bool dp[MAX_M]; |
| |
| int compute() { |
| for (int i = 1; i <= m; ++i) dp[i] = false; |
| dp[0] = true; |
| for (int i = 1; i <= n; ++i) { |
| if (cnt[i] == 1) { |
| |
| |
| for (int j = m; j >= value[i]; j--) |
| if (dp[j - value[i]]) |
| dp[j] = true; |
| } else if (value[i] * cnt[i] > m) { |
| |
| |
| for (int j = value[i]; j <= m; ++j) |
| if (dp[j - value[i]]) |
| dp[j] = true; |
| } else { |
| |
| |
| |
| for (int mod = 0; mod < value[i]; mod++) { |
| int trueCnt = 0; |
| for (int j = m - mod, size = 0; j >= 0 && size <= cnt[i]; j -= value[i], size++) |
| trueCnt += dp[j] ? 1 : 0; |
| for (int j = m - mod, l = j - value[i] * (cnt[i] + 1); j >= 1; j -= value[i], l -= value[i]) { |
| if (dp[j]) { |
| trueCnt--; |
| } else { |
| if (trueCnt != 0) dp[j] = true; |
| } |
| if (l >= 0) trueCnt += dp[l] ? 1 : 0; |
| } |
| } |
| } |
| } |
| int res = 0; |
| for (int i = 1; i <= m; i++) |
| if (dp[i]) res++; |
| return res; |
| } |
| |
| int main() { |
| cin >> n >> m; |
| while (n != 0 || m != 0) { |
| for (int i = 1; i <= n; ++i) cin >> value[i]; |
| for (int i = 1; i <= n; ++i) cin >> cnt[i]; |
| cout << compute() << endl; |
| cin >> n >> m; |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步