【dp】LGTB 玩THD

分享一道有趣的题

LGTB 玩THD

LGTB 最近在玩一个类似DOTA 的游戏名叫THD有一天他在守一座塔,对面的N 个小兵排成一列从近到远站在塔前面每个小兵有一定的血量hi,杀死后有一定的金钱gi每一秒,他都可以攻击任意一个活着的小兵,对其造成P 点伤害,如果小兵的血量低于1 点,小兵死亡,他得到金钱。他也可以不攻击任何小兵。每一秒LGTB 攻击完毕之后,塔会攻击距离塔最近的一个活着的小兵,对其造成Q 点伤害,如果小兵的血量低于1 点,小兵死亡,LGTB 不会得到金钱现在LGTB 想知道,在他选择最优策略时,他能得到多少钱。

输入

输入第一行包含3 个整数P, Q, N接下来N 行,每行包含2 个整数hi, gi第i 个小兵和塔之间的距离为i输入的意义如题面所示
对于20% 的数据,1< N< 4
对于50% 的数据,1< N< 20
对于100% 的数据,20< P,Q< 200, 1< N< 100, 1< hi< 200, 0< gi< 106

输出

输出包含一个整数W,代表LGTB 最多能获得的金钱

样例输入

20 60
380 100
80 200
120 300

样例输出

500


这道题一来就很崩溃,补兵按感觉补就行了为什么还要来写程序。。。算了,先不说这些,这道题一看就先想到dfs,但也一看就过不了,再一看可以看出很明显是dp,我写的和std不一样但还是可以A。
**我们可以认为,每一秒,我可以A兵,也可以把这一秒存起来,后面再用,这样就可以后面一秒5刀,6刀。我管这个现在一秒可以A几刀叫体力值k;我们还建立一个数组a,表示要额外消费多少点体力值可以补到刀,及a[i]=(塔最大攻击次数-人最小攻击次数)
再建立一个数组v,表示不A这个兵它最多抗几下。这时我们就可以开始dp了。设f[i][j][k]表示前i个兵,补j个刀,剩余体力值为k的最大获得金钱。**
f[i][j][k]=max(不补这个兵的最大钱,补这个兵的最大钱)
f[i][j][k]=max(f[i-1][j][k-v[i]],f[i-1][j-1][k+a[i]]+g[i])
大概就是这样,下面是代码,可以参考。

#include<cstdio>
#include<cstring>
#define M 101

using namespace std;

int P,Q,n,h[M],g[M],aa[2*M],vv[2*M],a[M],v[M],f[M][M][10*M],m;

int main()
{
    freopen("thd.in","r",stdin);
    freopen("thd.out","w",stdout);
    cin>>P>>Q>>n;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&h[i],&g[i]);
    for(int i=1;i<=P;i++)
        aa[i]=1;
    for(int i=P+1;i<=Q;i++)
        aa[i]=(i-P-1)/P+2;
    for(int i=Q+1;i<=200;i++)
        aa[i]=aa[i-Q]-1;
    for(int i=1;i<=200;i++)
        vv[i]=(i-1)/Q+1;
    for(int i=1;i<=n;i++)
    {
        a[i]=aa[h[i]];//求a与v 
        v[i]=vv[h[i]];
        m+=v[i];
    }
    if(n==1&&a[1]==1)
    {
        cout<<g[1];
        return 0;
    }
    m+=2;
    memset(f,-63,sizeof(f));//初始化为大负值 
    int v_sum=0;
    for(int i=1;i<=n;i++)
    {
        v_sum+=v[i];
        f[i][0][v_sum+1]=0;//初始化不补兵的情况 
    }
    if(a[1]<=1)
    f[1][1][-a[1]+1]=g[1];
    for(int i=2;i<=n;i++)
        for(int j=1;j<=i;j++)
            for(int k=0;k<=m;k++)
                if(k-v[i]>=0&&i-1>=j)
                    f[i][j][k]=max(f[i-1][j][k-v[i]],f[i-1][j-1][k+a[i]]+g[i]);
                else f[i][j][k]=f[i-1][j-1][k+a[i]]+g[i];
    int i=n,mx=0;
    for(int j=1;j<=i;j++)
            for(int k=0;k<=m;k++)
            {
                mx=max(mx,f[i][j][k]);
            }

    cout<<mx;
    return 0;

}

大概就这样,如果有什么问题,或错误,请在评论区提出,谢谢。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值