Gym 101161H Witcher Potion 状压dp

62 篇文章 0 订阅

题目链接: http://codeforces.com/gym/101161/attachments

题意:

你在初始状态下有 100 100 100 点能量, 0 0 0 点毒素值,你现在要连续的打小怪兽,打每只小怪兽需要花费你 K K K 点能量和 M M M 单位时间。你现在有 n ( n < = 8 ) n(n<=8) n(n<=8) 瓶药水,每瓶药水只能喝一次,并且在打一只小怪兽时最多喝一瓶,每瓶药水有一个增加的能量 e n e r g y [ i ] energy[i] energy[i] 和一个毒素增加值 p o t i o n [ i ] potion[i] potion[i] ,你体内的毒素如果大于等于 100 100 100 ,你会立刻死亡,每过单位时间毒素会减少 1 1 1 ,增加后能量不超过 100 100 100,毒素减少不低于 0 0 0 ,问你最多能打几只小怪兽。

做法:

d p [ s ] [ i ] [ j ] [ k ] dp[s][i][j][k] dp[s][i][j][k] 表示在喝药状态为 s s s 的状态下,你有能量 i i i 点,毒素为 j j j 时能打小怪兽的最大值, k k k 表示在这个状态下是否吃了药。(因为我们不知道在这个状态下我们打小怪兽的时候是不是已经吃过药了,所以需要一维控制)。

然后根据题意进行转移即可。

代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
using namespace std;
const int inf=1e9+7;
const int maxn=100005;
const int maxm=(1<<8);
int dp[maxm+5][105][105][2];
//嗑药状态为i 当前体力为j时 毒性为k时 是否吃过药 能打的最多小怪兽数量
int Eng[10],Pot[10],n,K,M;
int main(){
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d%d",&K,&M);
        scanf("%d",&n);
        rep(i,0,n-1) scanf("%d",&Eng[i]);
        rep(i,0,n-1) scanf("%d",&Pot[i]);
        for(int i=0;i<=100;i++)
            for(int j=0;j<(1<<n);j++)
                for(int k=0;k<=100;k++) dp[j][i][k][0]=dp[j][i][k][1]=-inf;
        dp[0][100][0][0]=0;
        int ans=0;
        for(int s=0;s<(1<<n);s++){
            for(int i=100;i>=1;i--){
                for(int j=99;j>=0;j--){
                    for(int k=0;k<=1;k++){
                        if(dp[s][i][j][k]==-inf) continue;
                        int ni=i-K,nj=max(j-M,0),ns;

                        if(i>K) {
                            dp[s][ni][nj][0]=max(dp[s][ni][nj][0],dp[s][i][j][k]+1);
                            ans=max(ans,dp[s][ni][nj][0]);
                        }
                        if(k!=0) continue;
                        for(int p=0;p<n;p++){
                            if(s&(1<<p)||j+Pot[p]>=100) continue;
                            ns=s|(1<<p); ni=min(100,i+Eng[p]); nj=j+Pot[p];
                            dp[ns][ni][nj][1]=max(dp[ns][ni][nj][1],dp[s][i][j][k]);
                            ans=max(ans,dp[ns][ni][nj][1]);
                        }
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值