题意 : 题目链接
分析 :
如果没有 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\n", ans); } return 0; }