poj1568 Find the Winning Move

来源:互联网 发布:中国万网域名申请流程 编辑:程序博客网 时间:2024/06/05 20:34

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.

Source


Mid-Central USA 1999

Solution


两个绝顶聪明的人玩4*4的(井字棋),现在轮到x下,问下哪里保证赢

花了几天大概搞懂了极大极小搜索和ab剪枝,感觉还是很不错的。这篇就讲得很好

说一下自己的理解吧。我们给每个局面定义一个对先手而言的价值f,那么贪心地想,先手一定会选择最大的一步f走,后手一定会选择最小的一步f走。这样一来整棵搜索树就是确定的了。

ab剪枝就是用兄弟的f来剪去当前不必要的决策点

本题还有一个强力的剪枝就是如果少于4个棋子就直接和局

Code


#include <stdio.h>#include <string.h>#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)#define max(x, y) ((x)>(y)?(x):(y))#define min(x, y) ((x)<(y)?(x):(y))#define INF 0x3f3f3f3fchar mp[5][5], opt[2];bool check(char ch) {    rep(i, 1, 4) {        bool flag = true;        rep(j, 1, 4) {            if (mp[i][j] != ch) {                flag = false;                break;            }        }        if (flag) {            return true;        }    }    rep(j, 1, 4) {        bool flag = true;        rep(i, 1, 4) {            if (mp[i][j] != ch) {                flag = false;                break;            }        }        if (flag) {            return true;        }    }    bool flag = true;    rep(i, 1, 4) {        if (mp[i][i] != ch) {            flag = false;            break;        }    }    if (flag) {        return true;    }    flag = true;    rep(i, 1, 4) {        if (mp[i][5 - i] != ch) {            flag = false;            break;        }    }    if (flag) {        return true;    }    return false;}int findMin(int dep, int alpha);int findMax(int dep, int beta) {    if (check('o')) {        return -INF;    }    if (dep == 16) {        return 0;    }    int ret = -INF;    rep(i, 1, 4) {        rep(j, 1, 4) {            if (mp[i][j] == '.') {                mp[i][j] = 'x';                int val = findMin(dep + 1, ret);                mp[i][j] = '.';                ret = max(ret, val);                if (ret >= beta) {                    return ret;                }            }        }    }    return ret;}int findMin(int dep, int alpha) {    if (check('x')) {        return INF;    }    if (dep == 16) {        return 0;    }    int ret = INF;    rep(i, 1, 4) {        rep(j, 1, 4) {            if (mp[i][j] == '.') {                mp[i][j] = 'o';                int val = findMax(dep + 1, ret);                mp[i][j] = '.';                ret = min(ret, val);                if (ret <= alpha) {                    return ret;                }            }        }    }    return ret;}void solve(int cnt) {    if (cnt <= 4) {        puts("#####");        return ;    }    int ret = -INF;    rep(i, 1, 4) {        rep(j, 1, 4) {            if (mp[i][j] == '.') {                mp[i][j] = 'x';                int val = findMin(cnt + 1, ret);                mp[i][j] = '.';                ret = max(ret, val);                if (ret == INF) {                    printf("(%d,%d)\n", i - 1, j - 1);                    return ;                }            }        }    }    puts("#####");}int main(void) {    scanf("%s", opt);    while (opt[0] != '$') {        int cnt = 0;        rep(i, 1, 4) {            scanf("%s", mp[i] + 1);            rep(j, 1, 4) {                if (mp[i][j] != '.') {                    cnt ++;                }            }        }        solve(cnt);        scanf("%s", opt);    }    return 0;}
原创粉丝点击