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;
}