题意:给出一个棋盘,x为先手,问是否有必胜策略,如果有输出第一步的坐标(如果有多种必胜策略,输出字典序最小);
对博弈问题生疏的可以搜一下“极大极小过程”;
#include<iostream>
using namespace std;
#define M 600000
int now[4][4];
char g[5][5];
int bit[20], d[20], e, WW;
int vis[M]; // 记忆化搜索
void init() // 用3进制表示每一位的状态, 复杂度O(3^12)(没人至少走了两步);
{
int i;
bit[0] = 1;
for( i = 1; i <= 16; i++ )
bit[i] = 3*bit[i-1];
}
void toBig( int uu ) //这里把空格的状态转到图里, 原理和二进制一样
{
int x, y;
for( int i = 0; i < e; i++ ){
x = d[i]/4; y = d[i]%4;
now[x][y] = uu % 3;
uu /= 3;
}
}
int Win( int t ) //判断结果
{
int i, j, k, kk = 0;
for( i = 0; i < 4; i++ ){
k = 1;
for( j = 0; j < 4 && k; j++ ) //判断行
if( now[i][j] != !t + 1 )
k = 0;
if( k )
return -1;
k = 1;
for( int j = 0; j < 4 && k; j++ ) //判断列
if( now[j][i] != !t + 1 )
k = 0;
if( k ) return -1;
}
for( int i = 0; i < 4; i++ )//判断棋盘满了, x先手,如果棋盘满了和棋;
for( int j = 0; j < 4; j++ )
if( now[i][j] == 0 ) kk++;
if( kk == 0 ) return -1;
k = 1;
for( i = 0; i < 4 && k; i++ )//对角线
if( now[i][i] != !t + 1 )
k = 0;
if( k ) return -1;
k = 1;
for( i = 0; i < 4 && k; i++ )
if( now[i][3-i] != !t + 1 )
k = 0;
if( k ) return -1;
return 1;
}
int dfs( int u, int t, int deep )
{
if( vis[u] != 0 )
return vis[u];
int x, y, uu,temp;
toBig( u );
if( Win(t) == -1 ) return vis[u] = -1; //-1表示输了
uu = u;
for( int i = 0; i < e; i++ ){
x = d[i] / 4; y = d[i] % 4;
if( now[x][y] == 0 ){
uu += (t+1)*bit[i];
temp = -dfs( uu, !t, deep+1 ); //负号表示对方的反状态,
toBig( u ); //回溯很重要
uu -= (t+1)*bit[i];
if( temp == 1 ){ //只要有一步赢了, 必赢
if( deep == 0 )
WW = i;
return vis[u] = 1;
}
}
}
return vis[u] = -1;
}
int main()
{
char str[3];
init();
while( scanf( "%s", str ) == 1 ){
if( str[0] == '$' ) break;
WW = -1;
e = 0;
memset( vis, 0, sizeof(vis) );
for( int i = 0; i < 4; i++ ){
scanf( "%s", g[i] );
for( int j = 0; j < 4; j++ )
if( g[i][j] == '.' ){
now[i][j] = 0;
d[e++] = i*4+j; //记录空格的位置
}
else if( g[i][j] == 'x' )
now[i][j] = 1;
else now[i][j] = 2;
}
if( dfs( 0, 0, 0 ) == 1 )
printf( "(%d,%d)\n", d[WW]/4, d[WW]%4 );
else
printf( "#####\n" );
}
}