tlqtj
查看原帖
tlqtj
1101254
Louisdlee楼主2024/5/9 23:13

链接:原题

题目

给你一个 H×WH\times W 的网格,称 (i,j)(i,j) 表示网格从上往下数第 ii 行,从左往右第 jj 行的格子。

每个格子要么是空地(用 ' .. ' 表示),要么是障碍物(用 ' # ' 表示)。

把一个棋子放在 (1,1)(1,1) 的位置,两个人(这两人此后简称 “ FirstFirst ” ," SecondSecond ")轮流进行操作。

FirstFirst 先操作。

每次操作只能将棋子向下、右下、右这三个方向的其中一个移动一格。

移动最后一步棋的人获胜。

请问最终谁获胜?

题解

显然这是一个公平组合游戏,于是对于先手而言:

  • 一个状态能通过一次转移,转移到必败态,那么这个状态是必胜态

  • 一个状态通过一次转移,只能转移到必胜态,那么这个状态是必败态。

  • 如果一个状态没有后继状态,那么这个状态是一个必败态。

考虑搜索整张图,然后在 (1,1)(1,1) 处得到答案。

如果把棋子初始放在 (H,W)(H,W) , 那么这个状态为必败。

然后由 (H,W)(H,W) 的状态,慢慢扩散回去。

对于一个位置 (i,j)(i,j) ,如果 (i+1,j) , (i,j+1) , (i+1,j+1)(i+1,j)\:,\:(i,j+1)\:,\:(i+1,j+1) 其中有一个是障碍物,那么我们就不用它们的结果扩展 (i,j)(i,j)。

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define INF 1e18
const int N = 1000;
int dp[N][N];
char s[N][N];

void slove(){
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) 
         for (int j = 1; j <= m; j++) 
            cin >> s[i][j];
    
    dp[n][m] = -1;
    for (int i = n; i >= 1; i--)
        for(int j = m; j >= 1; j--) {
            if (i == n and j == m) continue;
            dp[i][j] = -1;
            if (i + 1 <= n and j + 1 <= m and dp[i + 1][j + 1] == -1 and s[i + 1][j + 1] == '.') dp[i][j] = 1;
            if (i + 1 <= n and dp[i + 1][j] == -1 and s[i + 1][j] == '.') dp[i][j] = 1;
            if (j + 1 <= m and dp[i][j + 1] == -1 and s[i][j + 1] == '.') dp[i][j] = 1;
        }

    int ans = dp[1][1];

    if (ans == -1) cout << "Second" << endl;
    else cout << "First" << endl;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    slove();
}
2024/5/9 23:13
加载中...