对给定局面,求后手是否必胜。由于 2^{20}\approx 10^6 ,遍历全部状态是可行的,且状态转移数不多(每个状态的转移数最多为 nm+n(m-1) ),所以是一个稀疏图,可以考虑记忆化搜索,可以用二进制状态压缩存储每个局面的搜索结果,时间复杂度为 O(nm2^{n+m}) ,空间复杂度为 O(2^{n+m}) 。根据博弈论局面的性质直接DFS即可。
#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%lld", &x)
typedef long long ll;
#define mn 1048580 // 2^{20}+4
#define N 0
#define P 1
ll n, m, t, s[mn]; // s[si]=N(0)先手必胜;s[si]=P(1)先手必败
#define O 0
#define X 1
struct state
{
bool a[22][22];
ll toi() //把a转化为二进制状态
{
ll r = 0;
for (ll i = 1, k = 1; i <= n; ++i)
{
for (ll j = 1; j <= m; ++j, k *= 2)
{
r += k * a[i][j];
}
}
return r;
}
} now;
ll dfs()
{
ll si = now.toi();
if (s[si] != -1) //记忆化剪枝
{
return s[si];
}
ll hasP = 0, numx = 0; //是否可以移动到P
for (ll i = 1; i <= n; ++i)
{
for (ll j = 1; j <= m; ++j)
{
numx += now.a[i][j] == X;
if (now.a[i][j] == O)
{
now.a[i][j] = X;
hasP |= dfs();
now.a[i][j] = O; //回溯
}
if (j < m && now.a[i][j] == O && now.a[i][j + 1] == O)
{
now.a[i][j] = now.a[i][j + 1] = X;
hasP |= dfs();
now.a[i][j] = now.a[i][j + 1] = O;
}
}
}
s[si] = hasP ? N : (numx == n * m ? N : P);
return s[si];
//一般的ICG就hasP?N:P就行了
}
char ans[] = "LV", q[22][22]; //先手N(0)=V,P(1)=L,先手VL;故后手LV
signed main()
{
for (ll i = 0; i < mn; ++i)
{
s[i] = -1; //表示未知
}
sc(n), sc(m);
dfs();
for (sc(t); t--;)
{
for (ll i = 1; i <= n; ++i)
{
scanf("%s", q[i] + 1);
}
for (ll i = 1; i <= n; ++i)
{
for (ll j = 1; j <= m; ++j)
{
now.a[i][j] = q[i][j] == 'O' ? O : X;
}
}
printf("%c\n", ans[s[now.toi()]]);
}
return 0;
}