对应 POJ 题目:点击打开链接
Time Limit: 3000MS | Memory Limit: 32768K | |
Total Submissions: 1028 | Accepted: 502 |
Description
Input
Output
Sample Input
? .... .xo. .ox. .... ? o... .ox. .xxx xooo $
Sample Output
##### (0,1)
题意:
通俗地讲就是四子棋,给出一个局面,轮到 'x' 下子,问 'x' 有没有必胜策略?如果有,输出 'x' 下一步下子的坐标(行列都由 0 开始);否则输出字符串 "#####"。
它这里对必胜是这样解释:按 (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1) ... 的顺序找到第一个可以使 'x' 取胜的坐标。比如第二个例子,尽管 'x' 在 (0, 3) 或 (2, 0) 下子可以一步取胜,但是它在 (0, 1) 下子也可以间接取胜( 'x' 在 (0, 1) 下子后,无论 'o' 在哪里下子,'x' 都可以在下一次取胜),'x' 的下一步应该是 (0, 1)。
思路:
alpha-beta 搜索基础应用(博弈基础:点击打开链接),用一对全局变量保存结果就可以。有个剪枝是如果给出的局面棋盘里的棋子数不大于 4 的话,就没有必要计算了,肯定没有必胜策略,因为题目说了 'x' 和 'o' 至少都下了 2 子。而且没有这个剪枝会 TLE,加了就 0 ms 通过,时限是 3 秒啊!差距也太大了吧~
#include <stdio.h> #include <stdlib.h> #include <string.h> char g[5][5]; int ansx; int ansy; // 如果当前局面 'x' 取胜则返回 1,'o' 取胜则返回 -1,否则返回 0 int judge() { int i, j; int xa = 0, xb = 0; // 判断主对角线 int ya = 0, yb = 0; // 判断副对角线 for(i = 0; i < 4; i++){ int ra = 0, rb = 0; // 判断行 int ca = 0, cb = 0; // 判断列 if(g[i][i] == 'x') xa += 1; else if(g[i][i] == 'o') xb += 1; if(g[i][3-i] == 'x') ya += 1; else if(g[i][3-i] == 'o') yb += 1; for(j = 0; j < 4; j++){ if(g[i][j] == 'x') ra += 1; else if(g[i][j] == 'o') rb += 1; if(g[j][i] == 'x') ca += 1; else if(g[j][i] == 'o') cb += 1; } if(ra == 4 || ca == 4 || xa == 4 || ya == 4) return 1; else if(rb == 4 || cb == 4 || xb == 4 || yb == 4) return -1; } return 0; } int alpha_beta(int player, int alpha, int beta) { int i, j; int flag; flag = judge(); if(flag) // 已经分出胜负 return flag; if(player){ for(i = 0; i < 4; i++){ for(j = 0; j < 4; j++){ if(g[i][j] == '.'){ int val; g[i][j] = 'x'; // 下子 val = alpha_beta(player^1, alpha, beta); g[i][j] = '.'; // 撤销 if(val > alpha){ alpha = val; ansy = i; ansx = j; } if(alpha >= beta) return alpha; } } } return alpha; } else{ for(i = 0; i < 4; i++){ for(j = 0; j < 4; j++){ if(g[i][j] == '.'){ int val; g[i][j] = 'o'; val = alpha_beta(player^1, alpha, beta); g[i][j] = '.'; if(val < beta) beta = val; if(alpha >= beta) return beta; } } } return beta; } } int main() { #if 0 freopen("in.txt","r",stdin); #endif char od[2]; while(scanf("%s", od), od[0] != '$'){ int i, j; int alpha = -1; int beta = 1; int ans; int count = 0; for(i = 0; i < 4; i++){ scanf("%s", g[i]); for(j = 0; j < 4; j++) if(g[i][j] != '.') count++; } if(count <= 4){ // 如果目前棋盘的棋子不大于 4 个,双方都无必胜策略 printf("#####\n"); continue; } ans = alpha_beta(1, alpha, beta); if(ans > 0) printf("(%d,%d)\n", ansy, ansx); else printf("#####\n"); } return 0; }