HDU - 3182 Hamburger Magi (坑了我一天的简单DP!!!)

题目描述:

点击打开链接

题意:有N个汉堡,你有一定的能量值E,每个汉堡有自己的价值v,并且制作需要花费一定的能量值e,但是有些汉堡制作需要先制作一些特定的汉堡才行,求怎样制作汉堡能够获得的最大的价值。
这题其实不难,但是我坑在了一个十分愚蠢的地方,很气,于是要写下这道题。首先状态是十分好设计,汉堡最多只有15个,那么直接采取状态压缩,dp[i][j]表示i状态下使用了j能量时获得的价值。直接枚举所有状态,加进汉堡时在检验一下是否能加,能加的话更新状态和答案。这题唯一的坑点在于在枚举状态时,存在某些状态本身不可行的情况。这个问题其实也非常好解决,先把所有状态的初值设为-1,dp[0][0]设为0,因为该状态必然可行,并且所有状态肯定是从该状态转移得来的,所以自然从dp[0][0]开始进行状态转移,那么所有可行的状态都会被赋值,所以对后面状态枚举时只需检验他是否为-1即可。这个方法其实我很快就想到了,但是我坑在了一个极为愚蠢的地方,我把ans初始化成了-1,但是存在所有状态都不可行的情况,这个时候无法转移,答案就是0,我居然想了那么久都没想到!!!
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXM=25;

int N,E;
int n[20];
int e[20];
int dp[1<<16][110];
vector<int > need[20];

int cal(int x)
{
    int hav=0;
    for (int i=1;i<=N;i++)
    {
        if (x&(1<<(i-1)))
            hav=hav+e[i];
    }
    return hav;
}
bool check(int state,int x)
{
    for (int i=0;i<(int)need[x].size();i++)
        if (!(state&(1<<(need[x][i]-1)))) return false;
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&E);
        for (int i=1;i<=N;i++)
            scanf("%d",&n[i]);
        for (int i=1;i<=N;i++)
            scanf("%d",&e[i]);
        int q;
        for (int i=0;i<20;i++)
            need[i].clear();
        for (int i=1;i<=N;i++)
        {
            scanf("%d",&q);
            int x;
            while(q--)
            {
                scanf("%d",&x);
                need[i].push_back(x);
            }
        }
        memset(dp,-1,sizeof(dp));
        dp[0][0]=0;
        int ans=0;//愚蠢的我被这里坑了。。。QAQ。
        for (int i=0;i<(1<<N);i++)
        {
            int hav=cal(i);
            if (dp[i][hav]!=-1)
            {
                for (int j=1;j<=N;j++)
                {
                    if (hav+e[j]>E) continue;
                    if (i&(1<<(j-1))) continue;
                    if (check(i,j))
                    {
                        int state=i|(1<<(j-1));
                        dp[state][hav+e[j]]=dp[i][hav]+n[j];
                        ans=max(ans,dp[state][hav+e[j]]);
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值