标签:inf mil 要求 names 出现 小明 价值 font 表示
<题目链接>
题目大意:
在一个水果篮里有n种水果,并且这些水果每一种都有一个美味度和一个卡路里的属性, 小明要从这些水果中选出来一些做一个水果沙拉, 并且要求他的水果沙拉的美味度是卡路里的k倍,问小明是否可以做出这么一个水果沙拉,若不能输出-1,否则输出复合要求的最大的美味值。
解题思路:
题目的限制条件为物品的价值总和与卡路里的比值要为K,这个控制,于是我们将卡路里总和乘到的右边,然后移项,可得(a1-k*b1)+(a2-k*b2)+……+(an-k*bn)=0。因此就将 (ai-k*bi)作为物品i的一个新的属性,就将本问题转化为了01背包问题, 将(ai-k*bi)看成物品的重量,ai为物品的价值,0为背包的总容量。但是如果这样的话,(ai-k*bi)会出现负数。
为了处理这个问题,有两种处理方案;
一:将等式两边同时+N,使得 (ai-k*bi)全部为正
二:用两个dp,正的跑一遍,负的跑一遍,然后在把它们相加就是答案,至于题目的限制条件,则可以通过取相同的 i 值来实现,因为dd[i]中的体积 i 为实际体积的相反数。
下面的是第二种方案:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int maxn = 20000; #define INF 0x3f3f3f3f int dp[maxn], dd[maxn]; struct node { int val, k; int cnt; }; int main() { int n, m; while (scanf("%d %d", &n, &m) != EOF) { node arr[110]; for (int i = 1; i <= n; i++) scanf("%d", &arr[i].val); for (int i = 1; i <= n; i++) { scanf("%d", &arr[i].k); arr[i].cnt = arr[i].val - m * arr[i].k; } memset(dp, -INF, sizeof(dp)); //初始化为负无穷是为了能够使dp[j]表示恰好装满 i 体积的情况 memset(dd, -INF, sizeof(dd)); dp[0] = dd[0] = 0; for (int i = 1; i <= n; i++) { if (arr[i].cnt >= 0) { for (int j = 11000; j >= arr[i].cnt; j--) { dp[j] = max(dp[j], dp[j - arr[i].cnt] + arr[i].val); } } else { arr[i].cnt = -arr[i].cnt; for (int j = 11000; j >= arr[i].cnt; j--) { dd[j] = max(dd[j], dd[j - arr[i].cnt] + arr[i].val); } } } int ans = -0x3f; for (int i = 0; i <= 11000; i++) { if (dp[i] == 0 && dd[i] == 0)continue; //因为ans初始化为-0x3f,所以要跳过dp[0]==dd[0]==0的情况 ans = max(ans, dd[i] + dp[i]); //因为dp[i],dd[i]表示恰好装满i容量的最大价值,所以,题目的限制条件:(ai-k*bi)的总和=0,就可以通过dd[i],dp[i]取相同的i值来实现 } ans == -0x3f ? printf("-1\n") : printf("%d\n", ans); } return 0; }
2018-07-28
codeforces 366C Dima and Salad 【限制性01背包】
标签:inf mil 要求 names 出现 小明 价值 font 表示
原文地址:https://www.cnblogs.com/00isok/p/9380339.html