HDU 3182 Hamburger Magi(状压DP)

Hamburger Magi

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1109    Accepted Submission(s): 414


Problem Description
In the mysterious forest, there is a group of Magi. Most of them like to eat human beings, so they are called “The Ogre Magi”, but there is an special one whose favorite food is hamburger, having been jeered by the others as “The Hamburger Magi”.
Let’s give The Hamburger Magi a nickname “HamMagi”, HamMagi don’t only love to eat but also to make hamburgers, he makes N hamburgers, and he gives these each hamburger a value as Vi, and each will cost him Ei energy, (He can use in total M energy each day). In addition, some hamburgers can’t be made directly, for example, HamMagi can make a “Big Mac” only if “New Orleams roasted burger combo” and “Mexican twister combo” are all already made. Of course, he will only make each kind of hamburger once within a single day. Now he wants to know the maximal total value he can get after the whole day’s hard work, but he is too tired so this is your task now!
 

Input
The first line consists of an integer C(C<=50), indicating the number of test cases.
The first line of each case consists of two integers N,E(1<=N<=15,0<=E<=100) , indicating there are N kinds of hamburgers can be made and the initial energy he has.
The second line of each case contains N integers V1,V2…VN, (Vi<=1000)indicating the value of each kind of hamburger.
The third line of each case contains N integers E1,E2…EN, (Ei<=100)indicating the energy each kind of hamburger cost.
Then N lines follow, each line starts with an integer Qi, then Qi integers follow, indicating the hamburgers that making ith hamburger needs.
 

Output
For each line, output an integer indicating the maximum total value HamMagi can get.
 

Sample Input
  
  
1 4 90 243 464 307 298 79 58 0 72 3 2 3 4 2 1 4 1 1 0
 

Sample Output
  
  
298
 



题意:

给你n个汉堡,每一个汉堡有价值Vi和制作做需要的能量消耗Ei,你有总共的能量E,问你用你的能量最大可以获得的价值是多少

并且这里每一个汉堡有制作的前提,有一些汉堡需要其他汉堡制作完成之后才能制作


解析:

这里各个点不要求排列的顺序,所以只需要一维的dp表示状态

DP[i]表示在状态i下最大的价值

DP[i|(1<<(j-1))]=max{dp[i|(1<<(j-1))],dp[i]+value[j]]}

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 20;
const int SMAX= 1<<16;
int cost[MAXN];
int value[MAXN];
int fronts[MAXN];
int dp[SMAX];


int main()
{
    int t;
    int n,c;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&c);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&value[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&cost[i]);
        }
        int num;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            int tmp;
            fronts[i]=0;
            for(int j=1;j<=num;j++)
            {
                scanf("%d",&tmp);
                fronts[i]=fronts[i]|(1<<(tmp-1));
            }
        }
        memset(dp,-1,sizeof(dp));
        dp[0]=0;  //用于初始情况下,将所有不需要前提的汉堡加进去
        int ans=0;
        for(int i=0;i<(1<<n);i++)  //正着搜
        {
            for(int j=1;j<=n;j++) //将j加入
            {
                if(dp[i]==-1) continue;  //关键,因为这里是从前往后遍历的,汉堡的前提就能体现在这里
                //类似于拓扑排序,先将没有前提的点放进去,在通过这些点延生,并且延生的条件当前点的前提都已经做好了(并且这个点前提的前提,
                //一定是已经做好了,因为这个点的前提的dp存在,说明这个点的前提也是又前提的前提延生过来的
                if((i&fronts[j])!=fronts[j]) continue;
                if((i&(1<<(j-1)))) continue;
                int tmp=i;
                int pay=0;
                int flag=0;

                for(int k=1;k<=n;k++)
                {
                    if(tmp&(1<<(k-1)))
                    {
                            pay+=cost[k];
                    }
                }
                if(pay+cost[j]>c||flag) continue;
                int now=(i|(1<<(j-1)));
                dp[now]=max(dp[now],dp[i]+value[j]);
                ans=max(ans,dp[now]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值