codevs四子连棋--搜索

来源:互联网 发布:移动协同软件最新版 编辑:程序博客网 时间:2024/05/16 16:11

【codevs1004】四子连棋

2016年6月12日5,0370

题目描述 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 namespacestd;
llread()
{
    llx=0,f=1;charch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    returnx*f;
}
int head,tail=2,ans=-1;
boolmp[10000005],last[1000005];
int xx[4]={0,0,1,-1},yy[4]={-1,1,0,0};
chara[5][5];
char q[1000005][5][5];
intstep[1000005];
bool valid(intx,inty,intt)
{
    if(x>4||y>4||x<1||y<1||a[x][y]=='O')return0;
    if(a[x][y]=='B'&&t==0)return0;
    if(a[x][y]=='W'&&t==1)return0;
    return1;
}
boolequal(chara,charb,charc,chard)
{
    if(a!=b||b!=c||c!=d)return0;
    return1;
}
bool check(chara[5][5])
{
    for(inti=1;i<=4;i++)
    {
        if(equal(a[i][1],a[i][2],a[i][3],a[i][4]))return1;
        if(equal(a[1][i],a[2][i],a[3][i],a[4][i]))return1;
    }
    if(equal(a[1][1],a[2][2],a[3][3],a[4][4]))return1;
    if(equal(a[1][4],a[2][3],a[3][2],a[4][1]))return1;
    return0;
}
intgethash(chara[5][5])
{
    intt=0,key=0;
    for(inti=1;i<=4;i++)
        for(intj=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;
        }
    returnkey;
}
void move(intx,inty)
{
    for(intk=0;k<4;k++)
    {
        inttx=x+xx[k],ty=y+yy[k];
        if(!valid(tx,ty,last[head]))continue;
        for(inti=1;i<=4;i++)
            for(intj=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(inti=1;i<=4;i++)
            for(intj=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];
    }
}
voidbfs()
{
    while(head!=tail)
    {
        for(inti=1;i<=4;i++)
            for(intj=1;j<=4;j++)
                if(q[head][i][j]=='O')
                    move(i,j);
        if(ans!=-1)return;
        head++;
    }
}
intmain()
{
    for(inti=1;i<=4;i++)
        scanf("%s",a[i]+1);
    for(inti=1;i<=4;i++)
        for(intj=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);
    return0;
}