http://acm.hdu.edu.cn/showproblem.php?pid=3033
(1)本题为分组背包问题,输入时将数据存入到结构体中:
struct node { int p[120], v[120], tot; }brand[12];
(2)每组至少要取一个,处理方式不叫特殊,自然也是本题的关键。首先要初始化:
for(i=1;i<12;i++) for(j=0;j<=m;j++) dp[i][j]=-(1<<28);
即除了 i=0 以外,均是非法数据(注意,i=0 的一组千万不能赋负无穷)。
之后是核心的部分:
for(i=1;i<=k;i++) for(j=0;j<brand[i].tot;j++) for(l=m;l>=brand[i].p[j];l--) { dp[i][l]=max(dp[i][l], dp[i][l-brand[i].p[j]]+brand[i].v[j]); // 规划1 dp[i][l]=max(dp[i][l], dp[i-1][l-brand[i].p[j]]+brand[i].v[j]); // 规划2 }
对于每一层 i (i>0)均有,初始值都是非法的(负无穷),若只有规划1处理,仍为非法。而经过“规划2”处理,有一部分的dp[i][l]变成了合法数值,这就保证了处理过至少一次的均为合法。但注意到规划2最多只能装进每一组中的一个(注意循环 j 和循环 l 的相对位置),而规划1可以装入一组中的任意多个(请仔细体会),故规划1也是必须的。
具体代码:
View Code
#include<stdio.h> #include<stdio.h> #include<algorithm> using namespace std; int n, m, k; struct node { int p[120], v[120], tot; }brand[12]; int dp[12][11000]; int main() { int i, j, k, l; int a, b, c; while(scanf("%d%d%d", &n, &m, &k)!=EOF) { for(i=0;i<12;i++) brand[i].tot=0; for(i=1;i<=n;i++) { scanf("%d%d%d", &a, &b, &c); brand[a].p[brand[a].tot]=b; brand[a].v[(brand[a].tot)++]=c; } for(i=1;i<12;i++) for(j=0;j<=m;j++) dp[i][j]=-(1<<28); for(i=1;i<=k;i++) { for(j=0;j<brand[i].tot;j++) for(l=m;l>=brand[i].p[j];l--) { dp[i][l]=max(dp[i][l], dp[i][l-brand[i].p[j]]+brand[i].v[j]); dp[i][l]=max(dp[i][l], dp[i-1][l-brand[i].p[j]]+brand[i].v[j]); } } if(dp[k][m]<0) printf("Impossible\n"); else printf("%d\n", dp[k][m]); } return 0; }
