题意:给出井字棋的当前状态和先手,问最终是谁会赢,或者是平局?
思路:将每一个状态用三进制压缩,设dp[S][now]为当前状态为S,下棋的人是now时的胜负状态,那么当前如果对方连成了3子,己方就输了,或者自己连城了3子,己方就赢了,或者是棋盘已满,则为平局。如果当前状态可以进入至少一个必败态,那么当前状态是必胜态,否则如果可以进入一个平局态,那么当前状态就是平局态,否则是必败态。
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1e5 + 10;
using namespace std;
char s[3];
int T, st, dp[maxn][3];
int dfs(int S, int now) {
int &ans = dp[S][now];
if(ans != -2) return ans;
int c[3][3], sum = 0;
for(int i = 2; i >= 0; i--) {
for(int j = 2; j >= 0; j--) {
c[i][j] = S % 3;
S /= 3;
if(c[i][j]) sum++;
}
}
int n1 = 0, n2 = 0;
for(int i = 0; i < 3; i++) {
if(c[i][0] == c[i][1] && c[i][1] == c[i][2]) {
if(c[i][0] == 1) n1++;
if(c[i][0] == 2) n2++;
}
if(c[0][i] == c[1][i] && c[1][i] == c[2][i]) {
if(c[0][i] == 1) n1++;
if(c[0][i] == 2) n2++;
}
}
if(c[0][0] == c[1][1] && c[1][1] == c[2][2]) {
if(c[0][0] == 1) n1++;
if(c[0][0] == 2) n2++;
}
if(c[2][0] == c[1][1] && c[1][1] == c[0][2]) {
if(c[1][1] == 1) n1++;
if(c[1][1] == 2) n2++;
}
if(n1 && now == 2) return ans = 0;
if(n1 && now == 1) return ans = 1;
if(n2 && now == 1) return ans = 0;
if(n2 && now == 2) return ans = 1;
if(sum == 9) return ans = -1; //平局
int win = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(c[i][j]) continue;
c[i][j] = now;
int nxt = 0;
for(int ii = 0; ii < 3; ii++) {
for(int jj = 0; jj < 3; jj++) {
nxt = nxt * 3 + c[ii][jj];
}
}
c[i][j] = 0;
int can = dfs(nxt, 3 - now);
if(!can) return ans = 1; //必胜
if(can == -1) win = 1;
}
}
if(!win) return ans = 0; //必败
else return ans = -1; //平局
}
int main() {
for(int i = 0; i < maxn; i++) {
for(int j = 0; j < 3; j++) {
dp[i][j] = -2;
}
}
scanf("%d", &T);
while(T--) {
int now = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%s", s);
int add;
if(s[0] == '.') add = 0;
else if(s[0] == 'x') add = 1;
else add = 2;
now = now * 3 + add;
}
}
scanf("%s", s);
if(s[0] == 'x') st = 1;
else st = 2;
int ans = dfs(now, st);
if(ans == 0) printf("%c win!\n", st == 1 ? 'o' : 'x');
if(ans == 1) printf("%c win!\n", st == 2 ? 'o' : 'x');
if(ans == -1) printf("tie!\n");
}
return 0;
}
本文介绍了一种使用三进制状态压缩和动态规划求解井字棋博弈的方法。通过将棋盘状态转换为整数,并递归分析每一步可能的结果,得出最优策略下比赛的结局。
1万+

被折叠的 条评论
为什么被折叠?



