0
点赞
收藏
分享

微信扫一扫

洛谷P2851 [USACO06DEC]The Fewest Coins G 题解 多重背包+完全背包

题目链接:​​https://www.luogu.com.cn/problem/P2851​​

解题思路:

对FJ做多重背包,对商人做完全背包。

这里比较困惑我的是背包的容量。其大小的思路来自 ​​IcproX大佬的分享​​

首先说一下,\(a\) 上界是 \(v_{max}^2\)

下面给出理由

若知\(v_{max}\), 则最多有\(v_{max}\)种不同货币

如果选用\(v_{max}\)张时, 则必有两者重复

如第一篇题解所说,设\({s_1, s_2, s_3, ....., s_n}\)表示前缀和。

则必有\(s_k - s_j = w* v_{max}\)

那么$s_k $可以用 \(s_j\) + \(w\)张\(v_{max}\) (此时最优)

最坏时为 \(v_{max}^2\)

示例代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 110, maxv = 30030, V = maxv - 1;
int f1[maxv], f2[maxv], n, T, c[maxn], num[maxn], ans = 0x3f3f3f3f;
void zero_one_pack(int c, int v, int f[]) {
for (int i = V; i >= c; i --)
f[i] = min(f[i], f[i-c]+v);
}
void complete_pack(int c, int v, int f[]) {
for (int i = c; i <= V; i ++)
f[i] = min(f[i], f[i-c]+v);
}
void multi_pack(int c, int v, int num, int f[]) {
if (c * num >= V) complete_pack(c, v, f);
else {
int x = 1;
while (x <= num) {
zero_one_pack(c*x, v*x, f);
num -= x;
x *= 2;
}
if (num) zero_one_pack(c*num, v*num, f);
}
}
int main() {
cin >> n >> T;
for (int i = 0; i < n; i ++) cin >> c[i];
for (int i = 0; i < n; i ++) cin >> num[i];
memset(f1+1, 0x3f, sizeof(int)*(maxv-1));
memset(f2+1, 0x3f, sizeof(int)*(maxv-1));
for (int i = 0; i < n; i ++) {
multi_pack(c[i], 1, num[i], f1);
complete_pack(c[i], 1, f2);
}
for (int i = 0; i+T < maxv; i ++) ans = min(ans, f1[i+T] + f2[i]);
if (ans == 0x3f3f3f3f) puts("-1");
else cout << ans << endl;
return 0;
}


举报

相关推荐

0 条评论