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

<题目链接>

题目大意:

在一个水果篮里有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
") : printf("%d
", ans);     

    }
    return 0;
}

2018-07-28

原文地址:https://www.cnblogs.com/00isok/p/9380339.html