博弈(alpha-beta 剪枝)—— POJ 1568 Find the Winning Move

来源:互联网 发布:mp3剪切合并大师 mac 编辑:程序博客网 时间:2024/06/06 13:07

对应 POJ 题目:点击打开链接

Find the Winning Move
Time Limit: 3000MS Memory Limit: 32768KTotal Submissions: 1028 Accepted: 502

Description

4x4 tic-tac-toe is played on a board with four rows (numbered 0 to 3 from top to bottom) and four columns (numbered 0 to 3 from left to right). There are two players, x and o, who move alternately with x always going first. The game is won by the first player to get four of his or her pieces on the same row, column, or diagonal. If the board is full and neither player has won then the game is a draw. 
Assuming that it is x's turn to move, x is said to have a forced win if x can make a move such that no matter what moves o makes for the rest of the game, x can win. This does not necessarily mean that x will win on the very next move, although that is a possibility. It means that x has a winning strategy that will guarantee an eventual victory regardless of what o does. 

Your job is to write a program that, given a partially-completed game with x to move next, will determine whether x has a forced win. You can assume that each player has made at least two moves, that the game has not already been won by either player, and that the board is not full. 

Input

The input contains one or more test cases, followed by a line beginning with a dollar sign that signals the end of the file. Each test case begins with a line containing a question mark and is followed by four lines representing the board; formatting is exactly as shown in the example. The characters used in a board description are the period (representing an empty space), lowercase x, and lowercase o. For each test case, output a line containing the (row, column) position of the first forced win for x, or '#####' if there is no forced win. Format the output exactly as shown in the example.

Output

For this problem, the first forced win is determined by board position, not the number of moves required for victory. Search for a forced win by examining positions (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), ..., (3, 2), (3, 3), in that order, and output the first forced win you find. In the second test case below, note that x could win immediately by playing at (0, 3) or (2, 0), but playing at (0, 1) will still ensure victory (although it unnecessarily delays it), and position (0, 1) comes first.

Sample Input

?.....xo..ox.....?o....ox..xxxxooo$

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,否则返回 0int 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 0freopen("in.txt","r",stdin);#endifchar 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;}




0 0
原创粉丝点击