题目链接 Hrbust 2320
用三进制来存储整个棋盘的状态。
设$dp[status][now]$为轮到$now$下棋的时候是必胜必败还是平局。
那么若当前能延伸出的所有状态中存在必败态的,则当前状态为必胜态。
否则看所有延伸出的所有状态中是否存在一个平局态,如果存在则当前状态为平局。
否则当前状态为必败态。
平局局面:当棋盘已经被下满并且没有任意$3$个棋子连起来的时候则平局。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 2e4 + 10; const char *sss = ".ox~"; int a[3][3]; int f[N][2]; char ch[2]; int T; int s, x; int ans; int calc(int a[3][3]){ int ret = 0; rep(i, 0, 2){ rep(j, 0, 2){ ret = ret * 3 + a[i][j]; } } return ret; } int solve(int s, int x){ if (~f[s][x]) return f[s][x]; int c[3][3]; memset(c, 0, sizeof c); int xx = s; dec(i, 2, 0){ dec(j, 2, 0){ c[i][j] = xx % 3; xx /= 3; }} if (c[0][0] && c[0][0] == c[0][1] && c[0][1] == c[0][2] && c[0][0] != x) return f[s][x] = 1; if (c[1][0] && c[1][0] == c[1][1] && c[1][1] == c[1][2] && c[1][0] != x) return f[s][x] = 1; if (c[2][0] && c[2][0] == c[2][1] && c[2][1] == c[2][2] && c[2][0] != x) return f[s][x] = 1; if (c[0][0] && c[0][0] == c[1][0] && c[1][0] == c[2][0] && c[2][0] != x) return f[s][x] = 1; if (c[0][1] && c[0][1] == c[1][1] && c[1][1] == c[2][1] && c[2][1] != x) return f[s][x] = 1; if (c[0][2] && c[0][2] == c[1][2] && c[1][2] == c[2][2] && c[2][2] != x) return f[s][x] = 1; if (c[0][0] && c[0][0] == c[1][1] && c[1][1] == c[2][2] && c[0][0] != x) return f[s][x] = 1; if (c[0][2] && c[0][2] == c[1][1] && c[1][1] == c[2][0] && c[0][2] != x) return f[s][x] = 1; int yy = 0; rep(i, 0, 2) rep(j, 0, 2) if (c[i][j] == 0) yy = 1; if (!yy) return f[s][x] = 0; int ff[11]; memset(ff, 0, sizeof ff); int cnt = 0; rep(i, 0, 2){ rep(j, 0, 2){ if (c[i][j]) continue; c[i][j] = x; int ss = calc(c); ++cnt; ff[cnt] = solve(ss, 3 - x); c[i][j] = 0; } } int ret0 = 0, ret2 = 0; rep(i, 1, cnt){ if (ff[i] == 1) ret2 = 1; else if (ff[i] == 0) ret0 = 1; } if (ret2) return f[s][x] = 2; else if (ret0) return f[s][x] = 0; else return f[s][x] = 1; } void init(){ rep(i, 0, 2){ rep(j, 0, 2){ scanf("%s", ch); if (ch[0] == ‘.‘) a[i][j] = 0; else if (ch[0] == ‘o‘) a[i][j] = 1; else if (ch[0] == ‘x‘) a[i][j] = 2; } } scanf("%s", ch); if (ch[0] == ‘o‘) x = 1; else x = 2; s = calc(a); } int main(){ memset(f, -1, sizeof f); scanf("%d", &T); while (T--){ init(); ans = solve(s, x); if (x == 2){ if (ans == 2) puts("x win!"); else if (ans == 1) puts("o win!"); else puts("tie!"); } else{ if (ans == 2) puts("o win!"); else if (ans == 1) puts("x win!"); else puts("tie!"); } } return 0; }