HDU 4939 Stupid Tower Defense 简单DP

题意:

  地图为长为n个单位长度的直线,每通过一个单位长度需要t秒。

  有3种塔,红塔可以在当前格子每秒造成x点伤害,绿塔可以在之后格子造成y点伤害,蓝塔可以使通过单位长度的时间增加z秒。

  让你安排塔的排列是造成的伤害最大。

思路:

  最开始想到dp,状态dp[i][r][g][b]表示:假设前i格放了r个红塔、g个绿塔和b个蓝塔,枚举第i+1格放什么。

  因为长度最大为1500,所以如果这样开状态的话,需要1500^4的空间,这显然是开不下的。

  后来想到,一种塔的数量可以表示成总数减去另外两种塔的数量,这样的话,就可以减掉一维,变成dp[i][g][b],还是会超空间。

  然后想到,红塔只在当前格子有效,所以不用记录有多少红塔,只需要知道有多少绿塔和蓝塔就好了,也不用记录当前是第几格。所以状态变成了dp[g][b]。

  但是,这样子时间复杂度仍然是n^3的,会超时。

  可以证明,如果存在红塔,放在后面一定比放在前面更优。所以,只需要dp前面有g个绿塔和b个蓝塔时候造成的最大伤害,然后在求解的时候计算出后面全是红塔。 所以,时间复杂度也变成了n^2。这样子就可以解了。

代码:

  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <string>
 8 #include <queue>
 9 #include <stack>
10 #include <vector>
11 #include <map>
12 #include <set>
13 #include <functional>
14 #include <time.h>
15 
16 using namespace std;
17 
18 typedef __int64 ll;
19 
20 const int INF = 1<<30;
21 const int MAXN = 1555;
22 
23 ll dp[MAXN][MAXN]; //dp[i][j]: 前面i+j个塔中,有i个green,j个blue
24 ll n, x, y, z, t;
25 
26 void solve() {
27     scanf("%I64d%I64d%I64d%I64d%I64d", &n, &x, &y, &z, &t);
28 
29     memset(dp, 0, sizeof(dp));
30     for (int i = 0; i < n; i++)
31         for (int j = 0; j+i < n; j++) {
32             dp[i+1][j] = max(dp[i+1][j], dp[i][j]+(i*y)*(t+j*z));
33             dp[i][j+1] = max(dp[i][j+1], dp[i][j]+(i*y)*(t+j*z));
34         }
35 
36     ll ans = 0;
37     for (int i = 0; i <= n; i++)
38         for (int j = 0; i+j <= n; j++)
39             ans = max(ans, dp[i][j]+((n-i-j)*(x+i*y))*(t+z*j));
40 
41     printf("%I64d
", ans);
42 }
43 
44 int main() {
45     #ifdef Phantom01
46         freopen("HDU4939.txt", "r", stdin);
47     #endif //Phantom01
48 
49     int T;
50     scanf("%d", &T);
51     for (int i = 1; i <= T; i++) {
52         printf("Case #%d: ", i);
53         solve();
54     }
55 
56     return 0;
57 }
View Code
原文地址:https://www.cnblogs.com/Phantom01/p/3909427.html