题目描述 Description
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
● ○ ●
○ ● ○ ●
● ○ ● ○
○ ● ○
输入描述 Input Description
从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。
输出描述 Output Description
用最少的步数移动到目标棋局的步数。
样例输入 Sample Input
BWBO
WBWB
BWBW
WBWO
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
hi
需要用到哈希判重。将局面看作16位的三进制数,转化为十进制后取模作为key,已经达到过的局面不再重复入队。
队列中存的是整个状态,包括两个空格的坐标,达到当前局面需要的步数,上一步走的是黑棋还是白棋。
黑白双方交替走棋
最终局面的判断要考虑全面,包括行、列、两种斜线。
新状态入队时,要更新与局面有关的所有元素。
由于一开始不能明确先走黑棋还是先走白棋,所以两种走法取最小值。
看到洛谷的讨论区里说,对于洛谷的数据,如果初始状态就是目标状态,则答案为1.
觉得毫无道理。
codevs加特判才能A,,,,
这个数据在本地=3,交上就是这样。。。
一定有什么奇奇怪怪的原因¥%…………&%……#¥……#……%¥&#%&¥¥……#%@!##@@¥!@%¥#……%¥#……¥%&*())()&……&¥%&¥%……#%#%@¥#%#¥……%&¥#%……#¥%……%¥&%……&%……&……*
代码先贴着
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int mod=1000000+9999;
int dx[]={0,0,1,0,-1},dy[]={0,1,0,-1,0};
char s[5][5];
bool vis[1956781];
struct node
{
int x1,y1,x2,y2,a[5][5],step,up;
}re;
bool can(int x,int y)//是否可行
{
if(x<1||y<1||x>4||y>4) return 0;
return 1;
}
bool equal(int a,int b,int c,int d)//判断四个数是否相等
{
if(a!=b||b!=c||c!=d) return 0;
return 1;
}
bool pd(node now)//判断是否为最终局面
{
if(equal(now.a[1][1],now.a[2][2],now.a[3][3],now.a[4][4])) return 1;
if(equal(now.a[1][4],now.a[2][3],now.a[3][2],now.a[4][1])) return 1;
for(int i=1;i<=4;i++)
{
if(equal(now.a[i][1],now.a[i][2],now.a[i][3],now.a[i][4])) return 1;
if(equal(now.a[1][i],now.a[2][i],now.a[3][i],now.a[4][i])) return 1;
}
return 0;
}
int hash(node now)
{
int key=0;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
key=(key*3+now.a[i][j])%mod;
return key;
}
int bfs()
{
memset(vis,0,sizeof(vis));
queue<node>q;
while(!q.empty()) q.pop();
re.step=0;
q.push(re);
vis[hash(re)]=1;
while(!q.empty())
{
node now=q.front();
q.pop();
if(pd(now)) return now.step;
else
for(int i=1;i<=8;i++)
{
int fx,fy;
if(i<=4) fx=now.x1+dx[i],fy=now.y1+dy[i];
else fx=now.x2+dx[i-4],fy=now.y2+dy[i-4];
node nxt=now;
if(can(fx,fy)&&now.a[fx][fy]==now.up)
{
if(i<=4) swap(nxt.a[fx][fy],nxt.a[now.x1][now.y1]);//保证两个空格都被搜到
else swap(nxt.a[fx][fy],nxt.a[now.x2][now.y2]);
if(!vis[hash(nxt)])//判重
{
if(i<=4) nxt.x1=fx,nxt.y1=fy;//更新下一个状态的每一个元素
else nxt.x2=fx,nxt.y2=fy;
nxt.step=now.step+1;
vis[hash(nxt)]=1;
nxt.up=3-now.up;
q.push(nxt);
}
}
}
}
}
int main()
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{
cin>>s[i][j];
if(s[i][j]=='O')
{
if(!re.x1) re.x1=i,re.y1=j;
else re.x2=i,re.y2=j;
re.a[i][j]=0;
}
else if(s[i][j]=='B') re.a[i][j]=1;
else if(s[i][j]=='W') re.a[i][j]=2;
}
int ans;
re.up=1;
ans=bfs();
re.up=2;
printf("%d\n",min(ans,bfs()));
return 0;
}