植物大战僵尸 [费用提前计算]

问题描述

   何老板喜欢玩植物大战僵尸,在游戏里有一条水平道路,道路的一端是入口,另一端是房子。僵尸会从道路的入口一端向房子一端移动。这条道路刚好穿过N块连续的空地。初始时,僵尸通过每块空地的时间是T秒。玩家可以在这N个空地中种植植物以攻击经过的僵尸,每块空地中只能种植一种植物。
   共有三种不同类型的植物,分别是红草、蓝草和绿草,作用分别是攻击、减速以及下毒。每种植物只能在僵尸通过它所在空地的这段时间内攻击到僵尸。
   当僵尸经过一块红草所在的空地时,每秒钟生命值会减少R点;当僵尸从一块蓝草所在的空地走出之后,通过每块空地的时间延长B秒;当僵尸从一块绿草所在的空地走出之后,每秒钟会因中毒减少G点生命值。蓝草的减速效果和绿草的下毒效果是可以累加的。也就是说,僵尸通过n块蓝草所在的空地之后,它通过每块空地的时间会变成T+B*n秒;僵尸通过n块绿草所在的空地之后,它每秒钟会因中毒失去G*n点生命值。注:减速和中毒效果会一直持续下去
何老板想知道:怎样在这N块空地里种植各种类型的植物,才能使通过的僵尸失去的生命值最大。输出这个最大值。

输入格式

一行,五个空格隔开的整数N、R、G、B、T

输出格式

一行,一个整数,即通过的僵尸失去的最大的生命值

这道题用DP,但是有后效性啊,怎么办呢?当然是选择费用提前计算[手动滑稽]。

显然:

①草地要摆满红草、绿草和蓝草

②如果要安排摆放的顺序,红草要放在最后面,因为它的效果没有持续性。

但是蓝草(减速)和绿草(中毒)就不一样了,因为它们的效果有持续性,所以它们的摆放顺序要看情况。因此,就设一个状态f[i][j],表示前i+j块草地中,有i块绿草和j块蓝草的情况下,僵尸所失去的最大生命值(不包括后面的红草所带来的杀伤值)。对于每一个状态,影响它的有两个状态:

①前i+j-1块草坪中,有i块绿草和j-1块蓝草。这样的话,它对f[i][j]的贡献值就为:f[i][j-1]+(i*B+T)*G*(j-1) —- i*B+T表示通过当前草地所花费的时间,G*(j-1)表示通过当前草地僵尸所失去的生命值

②前i+j-1块草坪中,有i-1块绿草和j块蓝草。这样的话,它对f[i][j]的贡献值就为:f[i-1][j]+((i-1)*B+T)*G*j —- (i-1)*B+T表示通过当前草地所花费的时间,G*j表示通过当前草地僵尸所失去的生命值

要使僵尸所失去的生命值最大,那么f[i][j]=max(①,②).

再加上后面的红草所带来的杀伤值,Ans=max{f[i][j]+(n-i-j)*(i*B+T)*(j*G+R)}.

代码

//代码里的状态和上面的分析略有不同
#include
#include
#define ll long long
using namespace std;
ll f[3][3000];
//f[i][j]表示在i+j块草地中有i块蓝草(减速b)和j块绿草(中毒g)  
int main(){
    ll n,r,g,b,t,ans=0;
    scanf("%lld%lld%lld%lld%lld",&n,&r,&g,&b,&t);
    for(ll i=0;i<=n;i++)
        for(ll j=0;j<=n;j++){
//由于题目空间限制,要用滚动数组
            ll tmp=i&1LL;
            if(i+j>n)break;
            if(i)f[tmp][j]=max(f[tmp][j],f[tmp^1][j]+(t+b*(i-1))*g*j);
            if(j)f[tmp][j]=max(f[tmp][j],f[tmp][j-1]+(t+b*i)*g*(j-1));
            if(n-i-j)ans=max(ans,f[tmp][j]+(n-i-j)*(t+b*i)*(r+j*g));
        }
    printf("%lld",ans);return 0;
}

你可能感兴趣的:(题解,动态规划与递推)