其实就是背包问题的一种应用,至于为什么起这么个名字,可以去问问神犇zhhx。。。
问题描述和01背包几乎一样,你有m元钱,有n个物品可供选择,每个物品都有各自的花费c和价值v,而且每件物品只可以选择一次,问在花费不超过m元的条件下,最大价值是多少。
嗯,就是和普通的01背包一样,不同之处在于数据范围,m,c<=10^9,n<=100,1<=v<=5。如果还和普通的背包一样,设dp[i][j]表示考虑完第i件物品,花费为j元的最大价值,显然是行不通的。
我们发现花费取值范围太大,而价值取值范围较小,可以交换一下状态和最优值,设dp[i][j]表示考虑完第i件物品,价值为j元时的最小花费,那么满足dp[i][j]<=m的最大的j就是答案。
然后就和普通的01背包没啥区别了,该滚动数组就滚动。
附一道题,可以考虑用这种方法做,NOIP2005普及组 采药:https://www.luogu.org/problemnew/show/P1048
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxv = 1e4 + 5; 8 9 int dp[maxv]; 10 11 int main() { 12 int m, n, c, v, mv = 10000, ans = 0; 13 scanf("%d%d", &m, &n); 14 memset(dp, 0x3f3f3f3f, sizeof(dp)); 15 dp[0] = 0; 16 for (int i = 1; i <= n; ++i) { 17 scanf("%d%d", &c, &v); 18 for (int j = mv; j >= v; --j) { 19 dp[j] = min(dp[j], dp[j - v] + c); 20 if (i == n && dp[j] <= m) ans = max(ans, j); 21 } 22 } 23 printf("%d", ans); 24 return 0; 25 }