HDU 1712 分组背包问题

http://acm.hdu.edu.cn/showproblem.php?pid=1712

物品分多组,每组中的每件都是冲突的,那么,背包问题变成,在某组中取一个,使得价值达到最大,或者这组一个都不取能使价值达到最大,在01背包基础上加一个循环就可以,在减去体积的时候依次减去每组每一个的体积,这里的体积正好对应纵坐标,所以不必再抽象成c[i]了,价值w[i]<-a[i][j];

问题
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
算法
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
使用一维数组的伪代码如下:
for 所有的组k
    for v=V..0
        for 所有的i属于组k
            f[v]=max{f[v],f[v-c[i]]+w[i]}
注意这里的三层循环的顺序,甚至在本文的第一个beta版中我自己都写错了。“for v=V..0”这一层循环必须在“for 所有的i属于组k”之外。这样才能保证每一组内的物品最多只有一个会被添加到背包中。
另外,显然可以对每组内的物品应用P02中“一个简单有效的优化”。
小结
分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。不少背包问题的变形都可以转化为分组的背包问题(例如P07),由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。

 1 #include<stdio.h>
 2 int max(int a,int b)
 3 {
 4     return a>b?a:b;
 5 }
 6 int main()
 7 {
 8     int i,k,j,n,m,dp[110],a[110][110];
 9     while(scanf("%d%d",&n,&m),n||m)
10     {
11        for(i=1;i<=n;i++)
12         for(j=1;j<=m;j++)
13           scanf("%d",&a[i][j]);
14        dp[0]=0;
15        for(i=1;i<110;i++)dp[i]=0;
16        for(k=1;k<=n;k++)
17         for(j=m;j>=0;j--)
18           for(i=0;i<=j;i++)
19         dp[j]=max(dp[j],dp[j-i]+a[k][i]);//这里体积正好对应纵坐标,所以k组中的i就是相对应物品中的体积,价值是a[k][i] 
20        printf("%d
",dp[m]);
21     }
22     return 0;
23 }
View Code
原文地址:https://www.cnblogs.com/huzhenbo113/p/3248681.html