https://ac.nowcoder.com/acm/contest/33191/M
题意
给定一个 n*m 的棋盘,每个位置有一个字符,共有 'A', 'B', '.'
三种字符。
在 (1, 1) 位置上有一个棋子,Alice 和 Bob 轮流移动这个棋子,每次移动只能向右或者向下走一个单位。
如果走到标有字符 ‘A’ 的格子,那么 Alice 胜利;如果走到 ‘B’,Bob 胜利;如果走到最右下角的格子,平局。
现在 Alice 想知道,自己是否在无论 Bob 如何操作的情况下都能 win? 都能 draw? 都能 lose?
1 ≤ N , M ≤ 500 1≤N,M≤500 1≤N,M≤500
思路
首先需要发现,如果一个格子的坐标之和为偶数的话,那么这个位置轮到 Alice 操作;否则 Bob 操作。
棋子只能向右或者向下走,如果轮到 Alice 操作:
- 发现右边的点或者下面的点是必胜点,那么 Alice 一定会走向必胜点,那么当前点也成为必胜点。
- 否则当前点是不确定点。
而 Bob 会阻止 Alice 达到其想要的状态:
- 但是如果要走的两个点都是必胜点的话,Bob 没有选择,那么当前点也会成为必胜点。
- 否则当前点是不确定点。
从最右下角往前推,把所有的必胜点都推出来,如果发现起点是必胜点,那么就一定能得到想要的状态;
否则就不能得到。
从后往前推只需要从最后一行到第一行,对于每一行从后往前即可,这样遍历到一个点时,其右边位置和下面位置都已经遍历确定过了。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define endl '\n'
const int N = 2010, mod = 1e9+7;
int T, n, m;
char a[N][N], f[N][N];
signed main(){
Ios;
cin >> T;
while(T--)
{
cin >> n >> m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >> a[i][j];
for(int k=n;k>=1;k--)
{
for(int j=m;j>=1;j--)
{
if(a[k][j] != '.' || k==n&&j==m) f[k][j] = a[k][j];
else if((k+j) % 2 == 0) //Alice走
{
//要走的点存在必胜点,当前点为必胜点
if(j+1<=m && f[k][j+1] == 'A' || k+1<=n && f[k+1][j] == 'A') f[k][j] = 'A';
else f[k][j] = '#';
}
else //Bob走
{
//要走的点都是必胜点,当前点为必胜点
if((j+1 > m || f[k][j+1] == 'A') && (k+1 > n || f[k+1][j] == 'A')) f[k][j] = 'A';
else f[k][j] = '#';
}
}
}
if(f[1][1] == 'A') cout << "yes ";
else cout << "no ";
for(int k=n;k>=1;k--)
{
for(int j=m;j>=1;j--)
{
if(a[k][j] != '.' || k==n&&j==m) f[k][j] = a[k][j];
else if((k+j) % 2 == 0)
{
if(j+1<=m && f[k][j+1] == '.' || k+1<=n && f[k+1][j] == '.') f[k][j] = '.';
else f[k][j] = '#';
}
else
{
if((j+1 > m || f[k][j+1] == '.') && (k+1 > n || f[k+1][j] == '.')) f[k][j] = '.';
else f[k][j] = '#';
}
}
}
if(f[1][1] == '.') cout << "yes ";
else cout << "no ";
for(int k=n;k>=1;k--)
{
for(int j=m;j>=1;j--)
{
if(a[k][j] != '.' || k==n&&j==m) f[k][j] = a[k][j];
else if((k+j) % 2 == 0)
{
if(j+1<=m && f[k][j+1] == 'B' || k+1<=n && f[k+1][j] == 'B') f[k][j] = 'B';
else f[k][j] = '#';
}
else
{
if((j+1 > m || f[k][j+1] == 'B') && (k+1 > n || f[k+1][j] == 'B')) f[k][j] = 'B';
else f[k][j] = '#';
}
}
}
if(f[1][1] == 'B') cout << "yes ";
else cout << "no ";
cout << endl;
}
return 0;
}
经验
- 必胜点
- 反推