codevs四子连棋--搜索

【codevs1004】四子连棋

2016年6月12日 5,037 0

题目描述 Description

在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。

 
 

 

输入描述 Input Description

输出描述 Output Description

用最少的步数移动到目标棋局的步数。

样例输入 Sample Input

BWBO
WBWB
BWBW
WBWO

样例输出 Sample Output

5

题解

这显然是一道搜索相关的题目,每次找到空白的格子,将其与四周的棋子进行交换

这类求最小步数的题目往往迭代深搜可以秒杀

如果使用广度搜索,由于总局面数达到4 * 10^7,我们需要对局面进行判重,剪除重复搜索的分枝

这就需要用到哈希表,将局面看做16位的三进制数,转换十进制后取模作为key

 

据说迭代深搜可以秒杀

本题代码不考虑哈希表冲突的情况,不过由于最少步数的情况较多,得到错解的可能性比较低

valid函数用于与空白格交换的格子的合法性

equal用于判断四个字符是否相等

check用于判断是否为最终局面

gethash用于计算局面的哈希值

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define inf 1000000000
#define ll long long
#define mod 9875321
using namespace std ;
ll read ( )
{
     ll x = 0 , f = 1 ; char ch = getchar ( ) ;
     while ( ch < '0' || ch > '9' ) { if ( ch == '-' ) f = - 1 ; ch = getchar ( ) ; }
     while ( ch >= '0' && ch <= '9' ) { x = x * 10 + ch - '0' ; ch = getchar ( ) ; }
     return x * f ;
}
int head , tail = 2 , ans = - 1 ;
bool mp [ 10000005 ] , last [ 1000005 ] ;
int xx [ 4 ] = { 0 , 0 , 1 , - 1 } , yy [ 4 ] = { - 1 , 1 , 0 , 0 } ;
char a [ 5 ] [ 5 ] ;
char q [ 1000005 ] [ 5 ] [ 5 ] ;
int step [ 1000005 ] ;
bool valid ( int x , int y , int t )
{
     if ( x > 4 || y > 4 || x < 1 || y < 1 || a [ x ] [ y ] == 'O' ) return 0 ;
     if ( a [ x ] [ y ] == 'B' && t == 0 ) return 0 ;
     if ( a [ x ] [ y ] == 'W' && t == 1 ) return 0 ;
     return 1 ;
}
bool equal ( char a , char b , char c , char d )
{
     if ( a != b || b != c || c != d ) return 0 ;
     return 1 ;
}
bool check ( char a [ 5 ] [ 5 ] )
{
     for ( int i = 1 ; i <= 4 ; i ++ )
     {
         if ( equal ( a [ i ] [ 1 ] , a [ i ] [ 2 ] , a [ i ] [ 3 ] , a [ i ] [ 4 ] ) ) return 1 ;
         if ( equal ( a [ 1 ] [ i ] , a [ 2 ] [ i ] , a [ 3 ] [ i ] , a [ 4 ] [ i ] ) ) return 1 ;
     }
     if ( equal ( a [ 1 ] [ 1 ] , a [ 2 ] [ 2 ] , a [ 3 ] [ 3 ] , a [ 4 ] [ 4 ] ) ) return 1 ;
     if ( equal ( a [ 1 ] [ 4 ] , a [ 2 ] [ 3 ] , a [ 3 ] [ 2 ] , a [ 4 ] [ 1 ] ) ) return 1 ;
     return 0 ;
}
int gethash ( char a [ 5 ] [ 5 ] )
{
     int t = 0 , key = 0 ;
     for ( int i = 1 ; i <= 4 ; i ++ )
         for ( int j = 1 ; j <= 4 ; j ++ )
         {
             if ( a [ i ] [ j ] == 'O' ) t = 0 ;
             if ( a [ i ] [ j ] == 'W' ) t = 1 ;
             if ( a [ i ] [ j ] == 'B' ) t = 2 ;
             key = ( key * 3 + t ) % mod ;
         }
     return key ;
}
void move ( int x , int y )
{
     for ( int k = 0 ; k < 4 ; k ++ )
     {
         int tx = x + xx [ k ] , ty = y + yy [ k ] ;
         if ( ! valid ( tx , ty , last [ head ] ) ) continue ;
         for ( int i = 1 ; i <= 4 ; i ++ )
             for ( int j = 1 ; j <= 4 ; j ++ )
                 a [ i ] [ j ] = q [ head ] [ i ] [ j ] ;
         swap ( a [ x ] [ y ] , a [ tx ] [ ty ] ) ;
         if ( mp [ gethash ( a ) ] ) continue ;
         mp [ gethash ( a ) ] = 1 ;
         tail ++ ;
         for ( int i = 1 ; i <= 4 ; i ++ )
             for ( int j = 1 ; j <= 4 ; j ++ )
                 q [ tail ] [ i ] [ j ] = a [ i ] [ j ] ;
         step [ tail ] = step [ head ] + 1 ;
         last [ tail ] = last [ head ] ^ 1 ;
         if ( check ( a ) ) ans = step [ tail ] ;
     }
}
void bfs ( )
{
     while ( head != tail )
     {
         for ( int i = 1 ; i <= 4 ; i ++ )
             for ( int j = 1 ; j <= 4 ; j ++ )
                 if ( q [ head ] [ i ] [ j ] == 'O' )
                     move ( i , j ) ;
         if ( ans != - 1 ) return ;
         head ++ ;
     }
}
int main ( )
{
     for ( int i = 1 ; i <= 4 ; i ++ )
         scanf ( "%s" , a [ i ] + 1 ) ;
     for ( int i = 1 ; i <= 4 ; i ++ )
         for ( int j = 1 ; j <= 4 ; j ++ )
             q [ 0 ] [ i ] [ j ] = q [ 1 ] [ i ] [ j ] = a [ i ] [ j ] ;
     last [ 0 ] = 0 ; last [ 1 ] = 1 ;
     bfs ( ) ;
     printf ( "%d" , ans ) ;
     return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值