http://acm.hdu.edu.cn/showproblem.php?pid=1114
完全背包的题目,要求输出最小价值。然后一定要把给出的背包重量全部用完。
就是问一个背包为k的大小,n件物品,能装的最小价值,并且一定是用了k个背包容量。
用dp[i]表示背包容量为i得时候,能收录的最小价值,
边界:dp[0] = 0; 没容量,啥都干不了
else dp[i] = inf。一开始初始化为无穷大。
转移的话,dp[i] = min(dp[i], dp[i - weight[j]] + val[j])
枚举的话,次循环要顺着枚举。
因为这样才能确保它是能使用多次(完全背包嘛)
为什么顺着枚举就可以了呢?
因为考虑一下,当物品的重量为5,背包重量是10的时候。
顺着枚举for (int j = 5; j <= 10; ++j) 的话,
j = 5的时候,物品能枚举到是否加入背包,然后j = 10的时候,物品再次被枚举是否加入这个背包,也就是重复使用了
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 10000 + 20; int dp[maxn]; int val[maxn]; int weight[maxn]; void work() { int a, b; scanf("%d%d", &a, &b); int num = b - a; int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d%d", &val[i], &weight[i]); } memset(dp, 0x3f, sizeof dp); dp[0] = 0; //拥有0元,啥都干不了 for (int i = 1; i <= n; ++i) { for (int j = weight[i]; j <= num; ++j) { dp[j] = min(dp[j], dp[j - weight[i]] + val[i]); } } if (dp[num] != inf) { printf("The minimum amount of money in the piggy-bank is %d. ", dp[num]); } else { printf("This is impossible. "); } } int main() { #ifdef local freopen("data.txt","r",stdin); #endif int t; scanf("%d", &t); while (t--) work(); return 0; }