牛客网 TaoTao要吃鸡 ( 0/1背包变形 )

题意 : 题目链接

分析 : 

如果没有 BUG (即 h == 0 的时候)就是一个普通的 0 / 1 背包

需要讨论一下 h != 0 的情况

此时有就相当于有物品是有特权的

而且背包装有特权的物品根据题目的要求是应当最后装的

也就是说特权物品装完之后背包将不再可装

所以特权物品肯定是只有一个的

数据量并不大,所以可以去枚举这个特权物品

那么如何知道在  没有装特权物品  之前的最佳选择方案?

答案就是用最小的可剩空间留给特权物品,然后其他空间去跑 0/1 背包

最小的可剩空间当然就是 h + m - 1,只留一个单位空间给特权物品即可

最后除了枚举的物品,其他的物品去跑背包容量为 h + m - 1 的 0/1 背包

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 10;
int w[maxn], v[maxn], dp[maxn<<1];
int C, n, m, h;

int main(void)
{
    while(~scanf("%d", &n) && n){
        scanf("%d %d", &m, &h), C = m + h;

        for(int i=1; i<=n; i++)
            scanf("%d %d", &w[i], &v[i]);

        int ans = 0;

        memset(dp, 0, sizeof(dp));
        for(int i=1; i<=n; i++)
            for(int j=C; j>=w[i]; j--)
                dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
        ans = dp[C];

        if(h != 0){///有 BUG 存在
            for(int k=1; k<=n; k++){///枚举特权物品
                memset(dp, 0, sizeof(dp));///记得初始化
                for(int i=1; i<=n; i++){
                    if(i == k) continue;///特权物品不在 0/1 背包过程中
                    for(int j=C-1; j>=w[i]; j--){
                        dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
                    }
                }
                ans = max(ans, dp[C-1] + v[k]);///最后维护最优值
            }
        }

        printf("%d
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/qwertiLH/p/8536617.html