DP练习题 植物大战僵尸 题解 动态规划+费用提前计算

题目描述

聪聪喜欢玩植物大战僵尸,在游戏里有一条水平道路,道路的一端是入口,另一端是房子。僵尸会从道路的入口一端向房子一端移动。这条道路刚好穿过 \(N\) 块连续的空地。初始时,僵尸通过每块空地的时间是 \(T\) 秒。玩家可以在这 \(N\) 个空地中种植植物以攻击经过的僵尸,每块空地中只能种植一种植物。

共有三种不同类型的植物,分别是红草、蓝草和绿草,作用分别是攻击、减速以及下毒。每种植物只能在僵尸通过它所在空地的这段时间内攻击到僵尸。

  • 当僵尸经过一块红草所在的空地时,每秒钟生命值会减少 \(R\) 点;
  • 当僵尸从一块蓝草所在的空地走出之后,通过每块空地的时间延长 \(B\) 秒;
  • 当僵尸从一块绿草所在的空地走出之后,每秒钟会因中毒减少 \(G\) 点生命值。

蓝草的减速效果和绿草的下毒效果是可以累加的。也就是说,

  • 僵尸通过 \(n\) 块蓝草所在的空地之后,它通过每块空地的时间会变成 \(T+B \times n\) 秒;
  • 僵尸通过 \(n\) 块绿草所在的空地之后,它每秒钟会因中毒失去 \(G \times n\) 点生命值。

注:减速和中毒效果会一直持续下去。

聪聪想知道:怎样在这 \(N\) 块空地里种植各种类型的植物,才能使通过的僵尸失去的生命值最大。输出这个最大值。

输入格式

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

输出格式

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

样例输入

3 3 3 3 3

样例输出

45

说明/提示

输入保证 \(N \le 3000\)\(R,G,B,T\) 均为不超过 \(100\) 的正整数。

题解

首先,\(N\) 块空地必须得都种上草,不然就浪费了。

其次,造成伤害的只有红草,有持续效果的是蓝草和绿草,所以为了让伤害尽可能地高,肯定是蓝草和绿草放前面,后面是连续的红草。

但是蓝草和绿草的放置顺序就没有办法直接确定了,所以我们可以定义状态 \(f[i][j]\),表示前 \(i+j\) 块草地中,有 \(i\) 块蓝草和 \(j\) 块绿草的情况下,僵尸所失去的最大生命值(不包括后面的红草所带来的杀伤值)。

对于每一个状态 \(f[i][j]\),它只有可能从以下两种状态转化而来:

  1. \(i+j-1\) 块草坪中,有 \(i\) 块蓝草和 \(j-1\) 块绿草,第 \(i+j\) 块草坪种绿草,此时僵尸经过第 \(i+j\) 块草坪造成的伤害的损耗为 \((i \times B + T) \times G \times (j - 1)\)
  2. \(i+j-1\) 块草坪中,有 \(i-1\) 块蓝草和 \(j\) 块绿草,第 \(i+j\) 块草坪种蓝草,此时僵尸经过第 \(i+j\) 块草坪造成的伤害的损耗为 \(((i-1) \times B + T) \times G \times j\)

所以

\[f[i][j] = \max \{ f[i][j-1] + (i \times B + T) \times G \times (j - 1) , f[i-1][j] + ((i-1) \times B + T) \times G \times j \} \]

\(i+j\) 块草地中有 \(i\) 块种蓝草,\(j\) 块种绿草的情况下,对于剩余 \(n-i-j\) 块种红草的草坪来说:

  • 经过每块红草的时间都为 \((i \times B + T\)
  • 经过每块红草收到的伤害是红草的物理伤害加上累积的毒伤 \(R + j \times G\)

所以经过后 \(n-i-j\) 块草坪的总伤害为

\[(n-i-j) \times (i \times B + T) \times (R + j \times G) \]

所以最终的答案为

\[\max \{ f[i][j] + (n-i-j) \times (i \times B + T) \times (R + j \times G) \} \]

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3030;
int n;
long long R, G, B, T, f[maxn][maxn], ans;
int main() {
    cin >> n >> R >> G >> B >> T;
    for (int i = 0; i <= n; i ++) {
        for (int j = 0; i+j <= n; j ++) {
            if (j) f[i][j] = max(f[i][j], f[i][j-1] + (i*B+T)*G*(j-1));
            if (i) f[i][j] = max(f[i][j], f[i-1][j] + ((i-1)*B+T)*G*j);
            ans = max(ans, f[i][j] + (n-i-j) * (i*B+T) * (R+j*G));
        }
    }
    cout << ans << endl;
    return 0;
}
posted @ 2020-09-03 20:51  quanjun  阅读(303)  评论(0编辑  收藏  举报