【codevs2006】Boss单挑战

这个题真恶心……好几个背包套起来……第一眼看这个题确实很懵逼,看完题解后恍然大悟,原来是好几个二维背包一起用

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n1,n2,t,n,m,hp,mp,sp,dhp,dmp,dsp,x;
int a[1010],dp[1010][1010],mg[12],mh[12],sg[12],sh[12],km[1010],ks[1010],dps[1010][1010],dpm[1010][1010];
inline void u(int &x,int y)//用于更新答案 
{
    if(x<y)
        x=y;
}
void solve()
{
    scanf("%d%d%d%d%d%d%d%d%d",&n,&m,&hp,&mp,&sp,&dhp,&dmp,&dsp,&x);
    memset(dps,0,sizeof(dps));
    memset(dpm,0,sizeof(dpm));
    memset(km,0,sizeof(km));
    memset(ks,0,sizeof(ks));
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&n1);
    for(int i=1;i<=n1;i++)
        scanf("%d%d",&mh[i],&mg[i]);
    scanf("%d",&n2);
    for(int i=1;i<=n2;i++)
        scanf("%d%d",&sh[i],&sg[i]);
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=mp;j++)
            u(km[i],dpm[i][j]);//km[i]表示i回合以内最多能用法术攻击进行多少点伤害,dpm[i][j]表示当进行i回合,魔法值为j的时候,最多用法术攻击产生多少点伤害 
        for(int j=0;j<=mp;j++)
        {
            u(dpm[i+1][min(j+dmp,mp)],dpm[i][j]);//假设这个回合选择恢复蓝量,回复的次数也算入攻击次数 
            for(int k=1;k<=n1;k++)//枚举攻击方式 
                if(j>=mh[k])//这个回合选择用这种方式攻击 
                    u(dpm[i+1][j-mh[k]],dpm[i][j]+mg[k]);
        }
    }
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=sp;j++)
            u(ks[i],dps[i][j]);//ks,dps与之前km,dpm含义基本相同,不过反应的是用怒气攻击时的情况 
        for(int j=0;j<=sp;j++)
        {
            u(dps[i+1][min(j+dsp,sp)],dps[i][j]+x);//我们把普攻当成回复药水,不过它可以提供一定的攻击值 
            for(int k=1;k<=n2;k++)
                if(j>=sh[k])
                    u(dps[i+1][j-sh[k]],dps[i][j]+sg[k]);
        }
    }
    int mi=1000000007;
    for(int i=0;i<=n;i++)//枚举法攻 
        for(int j=0;j<=n;j++)//怒攻 
            if(km[i]+ks[j]>=m)//找到最小攻击回合数(法+怒总回合) 
                mi=min(mi,i+j);
    memset(dp,182,sizeof(dp));
    dp[1][hp]=1;//dp[i][j]表示在i个回合内,血量值为j的时候最多能攻击多少回合 
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=hp;j++)
            if(dp[i][j]>=mi)//如果发现能攻击的回合数已经满足最小攻击回合数,则满足条件 
            {
                printf("Yes %d\n",i);return;
            }
        for(int j=1;j<=hp;j++)
        {
            if(min(hp,j+dhp)>a[i])//假设这回合嗑药 
                u(dp[i+1][min(hp,j+dhp)-a[i]],dp[i][j]);
            if(j>a[i])//假设攻击 
                u(dp[i+1][j-a[i]],dp[i][j]+1);
        }
    }
    for(int i=1;i<=hp;i++)
        if(dp[n+1][i]>=0)//如果能够展开攻击,说明还活着(因为尽可能保证生存) 
        {
            printf("Tie\n");return;
        }
    printf("No\n");//否则说明狗带了 
}
int main()
{
    scanf("%d",&t);
    while(t--)
        solve();
}

 

转载于:https://www.cnblogs.com/Loi-dfkdsmbd/articles/7760040.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值