题意:
面包师Lavrenty打算用馅料做几个面包,然后把它们卖掉。
Lavrenty有n克面团和m种不同的馅料。馅料种类的下标从1到m,他知道他的第i种馅料剩下ai 克,做一个第i种馅料的面包,恰恰需要bi克的i种馅料 和 ci 克的面团,同时这种面包可以卖di 块Tugrik。
他也可以做没有馅的面包。每个这样的面包需要c0克面团,可以卖d0块Tugrik。所以Lavrenty可以做任何数量的包子,用不同的馅料或者不用馅料,除非用完了面团和馅料。Lavrenty会扔掉烘培面包后剩下的所有多余材料。
求出Lavrenty可以赚取的Tugrik的最大数量。
思路:将问题转换为多重背包问题,将每种馅料打包成一共可以做成多少分(包括没有馅料的面包)
然后对每种(0-m)馅料进行选择
多重背包模板:
#include<bits/stdc++.h> using namespace std; const int MAXN = 1005; int w[MAXN]; // 重量 int v[MAXN]; // 价值 int s[MAXN]; // 物品数量 int f[MAXN]; // f[i][j], j重量下前i个物品的最大价值 int main() { int n; int m; // 背包重量 cin >> n >> m; for(int i = 1; i <= n; ++i) cin >> w[i] >> v[i] >> s[i]; for(int i = 1; i <= n; ++i) for(int j = m; j>=0; --j) for(int k = 1; k <= s[i]; ++k) if(j>=k*w[i]) f[j] = max(f[j], f[j-k*w[i]]+k*v[i]); cout << f[m] << endl; return 0; }
本题代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1005; int dp[maxn]; int s[maxn];// 物品数量 int w[maxn];// 价值 int v[maxn];// 体积 int main() { int n, m, c0, d0; int x1, x2, x3, x4; cin >> n >> m >> v[0] >> w[0]; s[0] = n; for (int i = 1; i <= m; i++) { cin >> x1 >> x2 >> v[i] >> w[i]; s[i] = x1 / x2; //可自制的馅料数量转换为物品的数量 } int ans = 0; for (int i = 0; i <= m; i++) { for (int j = n; j >= 0; j--) { for (int k = 1; k <= s[i]; k++) { if (j >= k * v[i]) { dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]); } } } } cout << dp[n] << endl; return 0; }
二进制优化
#include <bits/stdc++.h> using namespace std; const int maxn = 1005; int dp[maxn]; int s[maxn];// 物品数量 int w[maxn];// 价值 int v[maxn];// 体积 int main() { int n, m, c0, d0; int x1, x2, x3, x4; cin >> n >> m >> v[0] >> w[0]; s[0] = n; for (int i = 1; i <= m; i++) { cin >> x1 >> x2 >> v[i] >> w[i]; s[i] = x1 / x2; } int ans = 0; for (int i = 0; i <= m; i++) { for (int j = 1; j <= s[i]; s[i] -= j, j <<= 1) { for (int k = n; k >= j * v[i]; k--) { dp[k] = max(dp[k], dp[k - j * v[i]] + j * w[i]); } } for (int k = n; k >= s[i] * v[i]; k--) { dp[k] = max(dp[k], dp[k - s[i] * v[i]] + s[i] * w[i]); } } cout << dp[n] << endl; return 0; }