码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3535 AreYouBusy(混合背包)

时间:2014-10-31 13:54:12      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:acm   algorithm   dp   算法   

HDU3535 AreYouBusy(混合背包)

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

题意:

       给你n个工作集合,给你T的时间去做它们。给你m和s,说明这个工作集合有m件事可以做,它们是s类的工作集合(s=0,1,2s=0说明这m件事中最少得做一件,s=1说明这m件事中最多只能做一件,s=2说明这m件事你可以做也可以不做)。再给你ci和gi代表你做这件事要用ci的时间,能获得gi的快乐值。求在T的时间内你能获得的最大快乐值。

分析:

       首先如果存在最优解, 我们可以互换不同工作集合的处理顺序, 依然能得到最优解. 那么我们下面只需要处理每个单独的工作集合即可.

       令dp[i][j]==x表示处理完前i组工作集,所花时间<=j时的快乐值为x。每得到一组工作就进行一次DP,所以dp[i]为第i组的结果。下面对三种情况进行讨论。

       1.    该集合内至少要选1件工作时. 要保证至少选1个第i类工作, 可以从第i-1类的结果dp[i-1]来更新dp[i].也可以用           01背包的思想, 从本类的前一个工作更新后一个工作.

       初始化:dp[i]全为负无穷.(即-INF)

       状态转移方程为:

       dp[i][k]=max{dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }

       2.    该集合内最多选1件工作时. 只能从上一层的结果dp[i-1]来更新dp[i]了.(想想为什么)

       初始化:dp[i]==dp[i-1].

       状态转移方程为dp[i][k]=max{dp[i][k],dp[i-1][k-cost[j]]+val[k]}.

       3.    该集合内工作可以随便选. 这就是1个普通的01背包问题了.

       初始化:dp[i]==dp[i-1].

       状态转移方程为:

       dp[i][k]=max{dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }

 

       最终所求:dp[n][t]的值.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;
#define INF 1e8

int n;
int t;
int dp[maxn][maxn];
int cost[maxn];
int val[maxn];

int main()
{
    while(scanf("%d%d",&n,&t)==2)
    {
        memset(dp,0,sizeof(dp));

        for(int i=1;i<=n;i++)
        {
            int m,s;
            scanf("%d%d",&m,&s);
            for(int k=1;k<=m;k++)
                scanf("%d%d",&cost[k],&val[k]);

            if(s==0)//至少选1个的01背包问题
            {
                for(int j=0;j<=t;j++) dp[i][j]=-INF;

                for(int k=1;k<=m;k++)
                for(int j=t;j>=cost[k];j--)
                {
                    dp[i][j] = max( dp[i][j] , dp[i][j-cost[k]]+val[k] );  //1
                    dp[i][j] = max( dp[i][j] , dp[i-1][j-cost[k]]+val[k] );//2
                    //上面两句顺序互换就会出错!为什么?
                }
            }
            else if(s==1)//至多选1个的背包问题
            {
                for(int j=0;j<=t;j++) dp[i][j]=dp[i-1][j];

                for(int k=1;k<=m;k++)
                for(int j=t;j>=cost[k];j--)//j可以正序或逆序枚举
                    dp[i][j] = max( dp[i][j] , dp[i-1][j-cost[k]]+val[k] );
            }
            else if(s==2)//随便选的01背包问题
            {
                for(int j=0;j<=t;j++) dp[i][j]=dp[i-1][j];

                for(int k=1;k<=m;k++)
                for(int j=t;j>=cost[k];j--)//j只能逆序枚举
                    dp[i][j] = max( dp[i][j] , dp[i][j-cost[k]]+val[k] );
            }
        }

        int ans = max(dp[n][t],-1);
        printf("%d\n",ans);
    }
    return 0;
}

HDU 3535 AreYouBusy(混合背包)

标签:acm   algorithm   dp   算法   

原文地址:http://blog.csdn.net/u013480600/article/details/40652673

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!