杭电1712 分组背包

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1712

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cstdlib>
 6 #include <cmath>
 7 #include <set>
 8 #include <map>
 9 #include <vector>
10 using namespace std;
11 
12 int max(int a, int b)
13 {
14     return a > b ? a : b;
15 }
16 int main()
17 {
18     int n, m, i, j, k, a[110][110], dp[110];
19     while(~scanf("%d %d", &n, &m))
20     {
21         if(n == 0 && m == 0)
22             break;
23         for(i = 1; i <= n; i++)
24             for(j = 1; j <= m; j++)
25                 scanf("%d", &a[i][j]);
26         memset(dp, 0, sizeof(dp));
27         for(i = 1; i <= n; i++)
28         {
29             for(j = m; j > 0; j--)//一定要从大到小
30             {
31                 for(k = 0; k < j; k++)
32                     dp[j] = max(dp[j], dp[k] + a[i][j - k]);
33             }
34         }
35         printf("%d\n", dp[m]);
36     }
37     return 0;
38 }

 

问题

有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中“一个简单有效的优化”。

posted @ 2016-05-06 23:06  海无泪  阅读(132)  评论(0编辑  收藏  举报