1. 程式人生 > >codeforces 366C Dima and Salad 【限制性01背包】

codeforces 366C Dima and Salad 【限制性01背包】

轉化 相同 ret lse 方案 font ORC 背包 val

<題目鏈接>

題目大意:

在一個水果籃裏有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背包】