题意:
一个n×m的地图,地图上有些地方不能走,有些地方有分值(1/3/5)。两个玩家移动一个棋子,棋子只能向下、右、右下移动。棋子到达一个格子,这个格子的分值属于移动方。当棋子无法移动时,分数高的获胜,如果分数一样,无法移动者输。
有多组询问,每个询问给出一个起点,问先手赢还是后手赢。
这题我能玩一年。
设dp[i][j][0]代表先手从(i, j)出发所能获取的最大分值,设dp[i][j][1]代表后手从(i, j)出发所能获取的最大分值,g[i][j]代表(i, j)格上的分值。
以(i, j)从(i, j + 1)转移来为例,有
dp[i][j][0] = dp[i][j + 1][1] + g[i][j + 1]
dp[i][j][1] = dp[i][j + 1][0]
这样做太蛋疼了,因为最多从3个状态转移,可是不知道按什么标准选取状态。
取先手最大值?WA了。
先手最大值相等再取后手最小值?WA了。
此时,我们将两个状态转移方程做差,设dp[i][j] = dp[i][j][0] - dp[i][j][1]。
得到dp[i][j] = g[i][j + 1] - dp[i][j + 1]。
发现维护dp[i][j]最大值,即维护先手后手得分的差值的最大值,就可以了。
有个小处理,将无法移动的状态的先手dp[i][j][0] = -0.5,即dp[i][j] = -0.5,这样将同分情况化为直接比较得分,更方便点。
注意:
此题有一组数据,用C,S,B代替了H,F,I,注意读入。
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 105, inf = 0x3f3f3f3f; int n, m, g[maxn][maxn]; double dp[maxn][maxn]; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } inline int cread() { char ch = getchar(); for(; ch != '.' && ch != 'H' && ch != 'F' && ch != 'I' && ch != '#' && ch != 'C' && ch != 'S' && ch != 'B'; ch = getchar()); if(ch == '.') return 0; if(ch == 'H' || ch == 'C') return 1; if(ch == 'F' || ch == 'S') return 3; if(ch == 'I' || ch == 'B') return 5; if(ch == '#') return -1; } inline bool check(int x, int y) { return x <= n && y <= m && g[x][y] >= 0; } int main() { n = iread(); m = iread(); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) dp[i][j] = -inf, g[i][j] = cread(); for(int i = n; i >= 1; i--) for(int j = m; j >= 1; j--) if(g[i][j] >= 0) { bool flag = 1; if(check(i, j + 1)) { flag = 0; dp[i][j] = max(dp[i][j], g[i][j + 1] - dp[i][j + 1]); } if(check(i + 1, j)) { flag = 0; dp[i][j] = max(dp[i][j], g[i + 1][j] - dp[i + 1][j]); } if(check(i + 1, j + 1)) { flag = 0; dp[i][j] = max(dp[i][j], g[i + 1][j + 1] - dp[i + 1][j + 1]); } if(flag) dp[i][j] = -0.5; } int T = iread(); while(T--) { int x = iread(), y = iread(); printf(dp[x][y] > 0.0 ? "HAL\n" : "DAVE\n"); } return 0; }