http://acm.hdu.edu.cn/showproblem.php?pid=3449
(1)本题属于分组背包的类型,但对于每一组,需先买盒子才能买物品,盒子无价值,武平才有价值(其实盒子有价值也能做)。
如何保证买入物品时已经买入了盒子,且不会出现多次买同一个盒子的悲剧呢?有一种办法是,开一个新的数组d[100100],对于每个d[i], 先买下盒子 i,
再用剩余的钱继承原有的规划结果:
for(j=p;j<=w;j++) d[j]=dp[j-p];
然后一一装入该组各个物品,得到最优的 d[i] ,最后用来更新 dp[i] 。
(2)用来买盒子的钱不可用:if(d[k-c]!=-1) 表示盒子钱不能用来买物品(这很重要)。
故一开始就假设所有的钱都不能用(初始化):
memset(d, -1, sizeof(d));
具体代码:


#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n, w; int dp[100100], d[100100]; int main() { int i, j, k; int p, m, c, v; while(scanf("%d%d", &n, &w)!=EOF) { memset(dp, 0, sizeof(dp)); for(i=1;i<=n;i++) { scanf("%d%d", &p, &m); memset(d, -1, sizeof(d)); for(j=p;j<=w;j++) d[j]=dp[j-p]; for(j=1;j<=m;j++) { scanf("%d%d", &c, &v); for(k=w;k>=c;k--) if(d[k-c]!=-1) d[k]=max(d[k], d[k-c]+v); } for(j=0;j<=w;j++) dp[j]=max(dp[j], d[j]); } printf("%d\n", dp[w]); } return 0; }