poj1568 Find the Winning Move----Find the Winning Move极大极小搜索


Find the Winning Move
Time Limit: 3000MS   Memory Limit: 32768K
Total Submissions: 421   Accepted: 240

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
代码参考的这 http://blog.csdn.net/lencle/article/details/7088034
金华邀请赛那题或许就源自这题了。

极大极小搜索策略一般都是使用在一些博弈类的游戏之中:

这样策略本质上使用的是深度搜索策略,所以一般可以使用递归的方法来实现。在搜索过程中,对本方有利的搜索点上应该取极大值,而对本方不利的搜索点上应该取极小值。

极小值和极大值都是相对而言的。

在搜索过程中需要合理的控制搜索深度,搜索的深度越深,效率越低,但是一般来说,走法越好。

极大极小搜索可以分开写,也可以放在一起写。

#include <iostream>
#include <memory.h>
#include <stdio.h>
using namespace std;
#define inf 100000000
int state[5][5],chess,xi,xj;
char ch;
int minfind(int,int,int);
int maxfind(int,int,int);
bool over(int x,int y) {
     bool flag = false;
     int row[5],col[5];
     memset(row,0,sizeof(row));
     memset(col,0,sizeof(col));
     for (int i=0;i<4;i++)
         for (int j=0;j<4;j++) {
             if (state[i][j]=='x') {
                row[i]++;
                col[j]++;
             }
             if (state[i][j]=='o') {
                row[i]--;
                col[j]--;
             }
         }
     if (row[x]==-4 || row[x]==4 || col[y]==-4 || col[y]==4)
        flag = true;
     int tot1 = 0, tot2 = 0;
     for (int i=0;i<4;i++) {
         if (state[i][i]=='x') tot1++;
         if (state[i][3-i]=='x') tot2++;
         if (state[i][i]=='o') tot1--;
         if (state[i][3-i]=='o') tot2--;
     }
     if ((tot1==4 || tot1==-4) && x==y)        flag = true;
     if ((tot2==4 || tot2==-4) && x==3-y)      flag = true;
     return flag;
}
int maxfind(int x,int y,int mini) {
    int tmp, maxi = -inf;
	if (over(x,y)) return maxi;
	if (chess==16) return 0;
	for (int i=0;i<4;i++)
	    for (int j=0;j<4;j++)
            if (state[i][j]=='.') {
                       state[i][j]='x';
                       chess++;
                       tmp = minfind(i,j,maxi);
                       chess--;
                       state[i][j]='.';
                       maxi = max(maxi, tmp);
                       if (maxi>=mini) return maxi;// f(p)正无穷,先手必胜
            }
    return maxi;
}
int minfind(int x,int y,int maxi) {
    int tmp, mini = inf;
	if (over(x,y)) return mini;
	if (chess==16) return 0;
	for (int i=0;i<4;i++)
	    for (int j=0;j<4;j++)
            if (state[i][j]=='.') {
                       state[i][j]='o';
                       chess++;
                       tmp = maxfind(i,j,mini);
                       chess--;
                       state[i][j]='.';
                       mini = min(mini, tmp);
                       if (mini<=maxi) return mini;//f(p)负无穷,后手必胜
            }
    return mini;
}
bool tryit() {
     int tmp, maxi = -inf;
     for (int i=0;i<4;i++)
         for (int j=0;j<4;j++)
             if (state[i][j]=='.') {
                state[i][j] = 'x';
                chess++;
                tmp = minfind(i,j,maxi);
                chess--;
                state[i][j] = '.';
                if (tmp>=maxi) {
                       maxi = tmp;
                       xi = i; xj = j;
                }
	            if (maxi==inf) return true;//f(p)正无穷,先手必胜
             }
     return false;
}
int main() {
	while (scanf("%c",&ch)) {
		if (ch=='$') break;
		scanf("%c",&ch);

		chess = -4;
		for (int i=0;i<4;i++)
			for (int j=0;j<5;j++) {
				scanf("%c",&state[i][j]);
				chess += state[i][j]!='.';
			}
		if (chess<=4) {  //强力剪枝
                      printf("#####\n");
                      continue;
        }
        if (tryit()) printf("(%d,%d)\n",xi,xj);
        else printf("#####\n");
	}
	return 0;
}

Alpha-Beta搜索剪枝Alpha-Beta搜索剪枝Alpha-Beta搜索剪枝
一般来说,为了在搜索过程中引起剪枝,在递归过程中要向下传递两个参数。第1个参数是alpha,它表示当前搜索节点走棋的一方搜索到的最好值,任何比它小的值都没有意义。第2个值是beta,表示对手目前的劣势,这是对手所能承受的最还的结果,比它大的值都会被舍弃。

Alpha-Beta搜索剪枝算法如下:

输入:搜索深度、alpha、beta

输出:节点的最佳走法、及对应的最佳估值

函数形式:int alphaBetaSearch(int depth ,int alpha,int beta)

如果depth小于等于0

      调用评估函数,并将结果赋给value

      返回value值

否则

      生成当前所有合理的走法

      对每一个走法

           执行走法

           value= - alphaBetaSearch( depth-1 , -beta , -alpha);

           //注意函数前面有负值,且参数alpha,beta分别取负值并进行交换

           撤销走法

           如果 value>=beta             //使得可能引起的走法先被搜索,因为搜索的效率很大程度上取决于剪枝的效果

                  返回beta

          如果   value>alpha

                  alpha=value

                  如果 depth == Max_Depth

                  bestmove=mv

      返回alpha

调用形式:alphaBetaSearch(MaxDepth,-MaxValue,MaxValue)

写的代码跟这个思想不完全一样

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=(1<<30);
const int N=25;
int pw2[25],pw3[25];
map<int,int>rpw2;
//---------------------------------------------------------
struct point {
    int x,y;
}pt[N];
int m;
char g[5][5];
int ansx,ansy,score;
int ans[N],ct;
int hash[555555];
const int n=4;
bool check(int x,int y)
{
    int i=0;
    while(i<4&&g[x][i]==g[x][y]) i++;if(i>=4) return true;i=0;
    while(i<4&&g[i][y]==g[x][y]) i++;if(i>=4) return true;i=0;
    if(x==y)
    while(i<4&&g[i][i]==g[x][y]) i++;if(i>=4) return true;i=0;
    if(x+y==3)
    while(i<4&&g[i][3-i]==g[x][y]) i++;if(i>=4) return true;
    return false;
}
int maxmin(int state,int who,int now,int alpha,int beta,int dep) {

    if(hash[now]!=-inf) return hash[now];
    if(state==0) return hash[now]=0;///
    int maxval=-inf,minval=inf,val;
    for(int st=state;st;st-=st&(-st)) 
    {
        int i=st&(-st),x=rpw2[i];
        g[pt[x].x][pt[x].y]=(who==0?'x':'o');
        if(check(pt[x].x,pt[x].y)) val=who^1;
        else val=maxmin(state-i,who^1,now+(who+1)*pw3[x],maxval,minval,dep+1);
        g[pt[x].x][pt[x].y]='.';
        if(who==0&&val>beta) return val;
        if(who==1&&val<alpha) return val;
        maxval=max(maxval,val);
        minval=min(minval,val);

        if(dep==0&&val>0) {
            if(ansx>pt[x].x||(ansx==pt[x].x&&ansy>pt[x].y)) {
                ansx=pt[x].x; ansy=pt[x].y;
            }
        }
    }
    if(who==0) return hash[now]=maxval;
    else return hash[now]=minval;
}
void init() {
    pw2[0]=pw3[0]=1; rpw2.clear();
    for(int i=0;i<20;i++) pw2[i]=1<<i,rpw2[1<<i]=i;
    for(int i=1;i<15;i++) pw3[i]=pw3[i-1]*3;
}

int main()
{
    int i,j,t,cas=0;
    int st;
    char c[5];
    init();
    while(cin>>c)
    {
        if(c[0]=='$') break;
        m=0;
        for(i=0;i<n;i++) {
            scanf("%s",g[i]);
            for(j=0;j<n;j++) {
                if(g[i][j]=='.')pt[m].x=i,pt[m++].y=j;
            }
        }
        st=pw2[m]-1; //111111
        //score=-inf;
        for(i=0;i<pw3[m];i++) hash[i]=-inf;
        ansx=inf;///
        int ret=maxmin(st,0,0,-inf,inf,0);
        if(ret==0) puts("#####");
        else printf("(%d,%d)\n",ansx,ansy);
    }
    return 0;
}

/*
4
01.1
00..
.01.
...1
4
0.01
0.01
1..0
.1..
0
*/


 

 
 

你可能感兴趣的:(poj1568 Find the Winning Move----Find the Winning Move极大极小搜索)