[poj 1568]Find the Winning Move

Find the Winning Move

Time Limit: 3000MS

 

Memory Limit: 32768K

Total Submissions:1782

 

Accepted: 854

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.

.xxx

xooo

$

Sample Output

#####

(0,1)

题意:给你一个4*4的棋盘下四子棋,己方下x,对方下o,找出一个必胜局面,输出第一个落子点。

注:极大极小搜索一般用在博弈问题中,假定两位玩家都足够聪明的情况下,求出最终的得分。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
char mp[5][5];
char str[2] = {'o','x'};
bool check_h(int h,int me)//行判断
{
    if(mp[h][0] == str[me]&&mp[h][1] == mp[h][2]&&mp[h][2] == mp[h][3]&&mp[h][3] == mp[h][0])
        return true;
    return false;
}
bool check_l(int l,int me)//列判断
{
    if(mp[0][l] == str[me]&&mp[1][l] == mp[2][l]&&mp[2][l] == mp[3][l]&&mp[3][l] == mp[0][l])
        return true;
    return false;
}
bool check_x(int me)//对角判断
{
    if(mp[0][0] == mp[1][1]&&mp[1][1] == mp[2][2]&&mp[2][2] == mp[3][3]&&mp[0][0] == str[me])   return true;
    if(mp[0][3] == mp[1][2]&&mp[1][2] == mp[2][1]&&mp[2][1] == mp[3][0]&&mp[0][3] == str[me])   return true;
    return false;
}
bool win(int me)
{
    for(int i = 0; i < 4; i++)
        if(check_h(i,me))
        {
            //cout<<"check_h"<<':';
            //cout<<i<<' '<<me<<endl;
            return true;
        }
        else if(check_l(i,me))
        {
            //cout<<"check_l"<<':';
            //cout<<i<<' '<<me<<endl;
            return true;
        }
        else if(check_x(me))
        {
            //cout<<"check_x"<<':';
            //cout<<i<<' '<<me<<endl;
            return true;
        }
    return false;
}

int ans_x,ans_y,flag;//flag记录的是对应ans进入的深度
//看别人大佬的代码有点看不懂,只能这样强行判断了Orz.....
int spa()
{
    int res=0;
    for(int i=0; i<4; i++)
        for(int j=0; j<4; j++)
            if(mp[i][j] == '.')res++;
    return res;
}

int dfs(int me,int deep)
{
    if(!spa())  return 0;
    int minn = 1,maxn = -1;
    for(int i = 0; i < 4; i++)
    for(int j = 0; j < 4; j++)
    {
        if(mp[i][j] == '.')
        {
            mp[i][j] = str[me];
            if(win(me))
            {
                if(flag > deep)
                {
                    ans_x = i;
                    ans_y = j;
                    flag = deep;
                }
                if(flag == deep&&ans_x*3+ans_y > i*3+j)//深度相同时,判断哪个点更先
                {
                    ans_x = i;
                    ans_y = j;
                }
                mp[i][j] = '.';
                return me == 1?max(maxn,1):min(minn,-1);
            }
            if(me)  maxn = max(maxn,dfs(me^1,deep+1));
            else    minn = min(minn,dfs(me^1,deep+1));
            if(maxn == 1&&flag > deep)
            {
                ans_x = i,ans_y = j;
                flag = deep;
            }
            if(maxn == 1&&flag == deep&&ans_x*3+ans_y > i*3+j)
            {
                ans_x = i,ans_y = j;
            }
            mp[i][j] = '.';
        }
    }
    return me == 1?maxn:minn;
}
int main()
{
    char ch;
    while(scanf(" %c",&ch)&&ch != '$')
    {
        for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)scanf(" %c",&mp[i][j]);
        flag = 0x7fffffff;
        if(spa() >= 12) {cout<<"#####"<<endl;continue;}//加了这一行时间瞬间下来了23333
        if(dfs(1,0) == 1)  cout<<'('<<ans_x<<','<<ans_y<<')'<<endl;
        else cout<<"#####"<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值