zoukankan      html  css  js  c++  java
  • HDU1712:ACboy needs your help(分组背包模板)

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

    Problem Description
    ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the profit?
     
    
    Input
    The input consists of multiple data sets. A data set starts with a line containing two positive integers N and M, N is the number of courses, M is the days ACboy has.
    Next follow a matrix A[i][j], (1<=i<=N<=100,1<=j<=M<=100).A[i][j] indicates if ACboy spend j days on ith course he will get profit of value A[i][j].
    N = 0 and M = 0 ends the input.
     
    
    Output
    For each data set, your program should output a line which contains the number of the max profit ACboy will gain.
     
    
    Sample Input
    2 2
    1 2
    1 3
    2 2
    2 1
    2 1
    2 3
    3 2 1
    3 2 1
    0 0
     
    
    Sample Output
    3
    4
    6
    

     分组背包

    问题

    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(有依赖的背包问题)),由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。


    算法分析:

    这是我第一次接触分组背包。

    此题属于典型的分组背包,每组至多一个背包。

    看了背包9讲,直接用他上面所写的套上去就行了,三重循环记住每一重的意义~!!!

    代码如下:
    #include <iostream>
    using namespace std;
    int a[101][101],f[101];
    int main()
    {
        int n,m,i,j,k;
        while(cin >> n >> m && (n != 0 || m != 0))
        {
            memset(f,0,sizeof(f));
            for(i = 1; i <= n; i++)
                for(j = 1; j <= m; j++)
                    cin >> a[i][j];
            for(i = 1; i <= n; i++) //第一重循环:分组数
                for(j = m; j >= 0; j--) //第二重循环:容量体积
                    for(k = 0; k <= j; k++) //第三重循环:属于i组的k
                        f[j] = max(f[j],f[j-k]+a[i][k]);
            cout << f[m] << endl;
        }
        return 0;
    }
  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/3940332.html
Copyright © 2011-2022 走看看