poj1568 Find the Winning Move[极大极小搜索+alpha-beta剪枝]

Find the Winning Move

Time Limit: 3000MS   Memory Limit: 32768K
Total Submissions: 1286   Accepted: 626

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)

Source

Mid-Central USA 1999

#include<cstdio>
using namespace std;
char s[5][5];
int chess,X,Y;
inline int abs(int x){return x>0?x:-x;}
bool check(int x,int y){//判断一个局面是否结束
    int tot=0;
    for(int i=0;i<4;i++) s[x][i]==‘o‘?tot++:s[x][i]==‘x‘?tot--:tot;//横向判断
    if(abs(tot)==4) return 1;tot=0;
    for(int i=0;i<4;i++) s[i][y]==‘o‘?tot++:s[i][y]==‘x‘?tot--:tot;//纵向判断
    if(abs(tot)==4) return 1;tot=0;
    for(int i=0;i<4;i++) s[i][i]==‘o‘?tot++:s[i][i]==‘x‘?tot--:tot;//正对角线判断
    if(abs(tot)==4) return 1;tot=0;
    for(int i=0;i<4;i++) s[i][3-i]==‘o‘?tot++:s[i][3-i]==‘x‘?tot--:tot;//反对角线判断
    if(abs(tot)==4) return 1;
    return 0;
}
int Min(int ,int);
int Max(int ,int);
int Max(int x,int y){
    if(check(x,y)) return -1;//已经结束(对方胜)
    if(chess==16) return 0;//平局
    for(int i=0,now;i<4;i++){
        for(int j=0;j<4;j++){
            if(s[i][j]==‘.‘){
                s[i][j]=‘x‘;chess++;
                now=Min(i,j);
                s[i][j]=‘.‘;chess--;
                //对方需要找的最差估价,如果当前比之前最差的高,α剪枝
                if(now==1) return 1;
            }
        }
    }
    return -1;
}
int Min(int x,int y){
    if(check(x,y)) return 1;//已经结束(己方胜)
    if(chess==16) return 0;
    for(int i=0,now;i<4;i++){
        for(int j=0;j<4;j++){
            if(s[i][j]==‘.‘){
                s[i][j]=‘o‘;chess++;
                now=Max(i,j);
                s[i][j]=‘.‘;chess--;
                //自己需要找的最高估价,如果当前比之前最差的低,β剪枝
                if(!now||now==-1) return -1;
            }
        }
    }
    return 1;
}
bool solve(){
    for(int i=0,now;i<4;i++){
        for(int j=0;j<4;j++){//枚举,然后搜索
            if(s[i][j]==‘.‘){
                s[i][j]=‘x‘;chess++;
                now=Min(i,j);
                s[i][j]=‘.‘;chess--;
                if(now==1){
                    X=i;Y=j;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main(){
    char ch[3];
    while(~scanf("%s",ch)&&ch[0]==‘?‘){
        for(int i=0;i<4;i++) scanf("%s",s[i]);chess=0;
        for(int i=0;i<4;i++) for(int j=0;j<4;j++) chess+=s[i][j]!=‘.‘;
        if(chess<=4){puts("#####");continue;}//一定平局(对方都绝顶聪明的话)
        if(solve()) printf("(%d,%d)\n",X,Y);
        else puts("#####");
    }
    return 0;
}
时间: 2024-10-08 01:21:45

poj1568 Find the Winning Move[极大极小搜索+alpha-beta剪枝]的相关文章

五子棋AI算法第三篇-Alpha Beta剪枝

剪枝是必须的 上一篇讲了极大极小值搜索,其实单纯的极大极小值搜索算法并没有实际意义. 可以做一个简单的计算,平均一步考虑 50 种可能性的话,思考到第四层,那么搜索的节点数就是 50^4 = 6250000,在我的酷睿I7的电脑上一秒钟能计算的节点不超过 5W 个,那么 625W 个节点需要的时间在 100 秒以上.电脑一步思考 100秒肯定是不能接受的,实际上最好一步能控制在 5 秒 以内. 顺便说一下层数的问题,首先思考层数必须是偶数.因为奇数节点是AI,偶数节点是玩家,如果AI下一个子不考

C++alpha beta剪枝算法 实现4*4 tic-tac-toe

先上一张alpha beta原理图,一看就懂 代码有点长,主要是因为算评估值得时候用的是穷举. 玩家是1,电脑是2,可以选择难度以及先手. // // main.cpp // Tic-Tac-Toe // // Created by mac on 2017/4/2. // Copyright ? 2017年 mac. All rights reserved. // #include <iostream> #include <vector> #include <math.h&g

【poj1568】 Find the Winning Move

http://poj.org/problem?id=1568 (题目链接) 题意 两人下4*4的井字棋,给出一个残局,问是否有先手必胜策略. Solution 极大极小搜索.. 这里有个强力优化,若已经被下了的的格子数cnt小于等于4的话,那么一定是平局至于为什么,自己YY一下发现好像是这样的.. 代码 // poj1568 #include<algorithm> #include<iostream> #include<cstring> #include<cstd

【迭代博弈+搜索+剪枝】poj-1568--Find the Winning Move

poj  1568:Find the Winning Move   [迭代博弈+搜索+剪枝] 题面省略... 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

POJ Find the Winning Move【minmax搜索+alpha-beta剪枝】【北大ACM/ICPC竞赛训练】

1 #include<iostream> 2 using namespace std; 3 4 int row,col,chess; 5 char board[5][5]; 6 7 int minSearch(int i,int j,int alpha); 8 int maxSearch(int i,int j,int beta); 9 10 11 bool check(int r,int c){ 12 if( board[r][0]==board[r][1] && board

POJ 1568 Find the Winning Move

Find the Winning Move 链接 题意: 4*4的棋盘,给出一个初始局面,问先手有没有必胜策略? 有的话输出第一步下在哪里,如果有多个,按(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1) ... 的顺序输出第一个.没有输出“#####”. 分析: 极大极小搜索,对抗搜索,α+β剪枝. 代码: 1 #include<cstdio> 2 3 char g[5][5]; 4 int ansx,ansy; 5 6 int judge() {

POJ 1568 极大极小搜索 + alpha-beta剪枝

极小极大搜索 的个人理解(alpha-beta剪枝) 主要算法依据就是根据极大极小搜索实现的. 苦逼的是,查了两个晚上的错,原来最终是判断函数写错了..瞬间吐血! ps. 据说加一句 if sum < 4 printf("#####\n")会变态的快,不过懒得加了 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #includ

[CodeVs3196]黄金宝藏(状态压缩DP/极大极小搜索)

题目大意:给出n(≤500)个数,两个人轮流取数,每次可以从数列左边或者右边取一个数,直到所有的数被取完,两个人都以最优策略取数,求最后两人所得分数. 显然这种类型的博弈题,第一眼就是极大极小搜索+记忆化,但是我并不是很会极大极小搜索TAT.然后第二眼发现可以用状压写,而且显然比极大极小搜索好写啊.预处理出前缀和,然后f[i,j]表示从第i个数到第j个数先手可得到的最大得分,则有f[i,j]=sum[j]-sum[i-1]-min(f[i+1,j],f[i,j-1]);[第i个数到第j个数的和减

极大极小搜索思想+(α/β)减枝 【转自-----https://blog.csdn.net/hzk_cpp/article/details/79275772】

极大极小搜索,即minimax搜索算法,专门用来做博弈论的问题的暴力. 多被称为对抗搜索算法. 这个搜索算法的基本思想就是分两层,一层是先手,记为a,还有一层是后手,记为b. 这个搜索是认为这a与b的利益关系是对立的,即假设a要是分数更大,b就要是分数更小. 而且这两个人都是用最优策略. 对,就是这样. 假设我们现在有一道题,给出一串数列,有两个选手按顺序选数,也就是一个选手选了ai,接下来另一个选手就必须选ai后面的任意一个数,然后每个选手选的数的累加和即为选手的分数,求先手比后手最多多几分.