Solitaire


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3337    Accepted Submission(s): 1046


Problem Description


Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.


There are four identical pieces on the board. In one move it is allowed to:



> move a piece to an empty neighboring field (up, down, left or right),



> jump over one neighboring piece to an empty field (up, down, left or right).




HDU 1401 Solitaire 双向BFS_1401



There are 4 moves allowed for each piece in the configuration shown above. As an example let's consider a piece placed in the row 4, column 4. It can be moved one row up, two rows down, one column left or two columns right.



Write a program that:



> reads two chessboard configurations from the standard input,



> verifies whether the second one is reachable from the first one in at most 8 moves,



> writes the result to the standard output.



Input


Each of two input lines contains 8 integers a1, a2, ..., a8 separated by single spaces and describes one configuration of pieces on the chessboard. Integers a2j-1 and a2j (1 <= j <= 4) describe the position of one piece - the row number and the column number respectively. Process to the end of file.


 


Output


The output should contain one word for each test case - YES if a configuration described in the second input line is reachable from the configuration described in the first input line in at most 8 moves, or one word NO otherwise.


 


Sample Input


4 4 4 5 5 4 6 5 2 4 3 3 3 6 4 6



Sample Output


YES


/*
1401 双向BFS

普通广度优先搜索的复杂度:有4颗棋子,每个棋子最多有4种变换方式,
所以一个棋盘可以对应16种状态,走8步的话,就有16^8 = 2^32的计算量。

给定两种状态,判断是否可达。操作的特别之处:操作具有可逆性,
也就是说,从A到B状态,B到A依然是可行的。

可虑一下双向广搜,先判断复杂度:两个状态各进行4步操作,计算量为16^4=2^16,
时空复杂度都可以满足。
考虑到这里不要求最小步数,我们可以先把两种状态各走四步的可达状态先用广搜算出存表,
然后直接查表比较即可。
有一个剪枝的问题需要考虑,现在给4个piece编号,1,2,3,4.
如果在某种情况下存在{4,4}{4,5}{4,6}{4,7},之后又出现{4,4}{4,6}{4,5}{4,7},
虽然在hash表里不同,但实际上是重复的mode,因此需要给4个piece进行排序。
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;

const int dir[4][2] = {1,0,-1,0,0,1,0,-1};
const int pow[8] = {1,8,64,512,4096,32768,262144,2097152};

struct point{
int x,y;
};

struct node{
point chess[4];

bool check(int k)
{
if(chess[k].x>=0&&chess[k].x<=7&&chess[k].y>=0&&chess[k].y<=7)
{
for(int i=0;i<4;i++)
{
if(i!=k&&chess[i].x==chess[k].x&&chess[i].y==chess[k].y)
return false;
}
return true;
}
return false;
}
};

node s,e;
map<int,int> mm;
map<int,int>::iterator it1,it2;

bool cmp(struct point a,struct point b)
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}

int gethash(node& a)
{
sort(a.chess,a.chess+4,cmp);
int hash=0;
for(int i=0;i<4;i++)
{
hash+=a.chess[i].x*pow[2*i];
hash+=a.chess[i].y*pow[2*i+1];
}
return hash;
}

bool BFS(node temp,int flag)
{
queue<node> que;
int i,j;
que.push(temp);

while(!que.empty())
{
temp=que.front();
que.pop();

it1=mm.find(gethash(temp));
if((it1->second)%10>=4) //移动步数超过4步
continue;

for(i=0;i<4;i++)//四个棋子
{
for(j=0;j<4;j++)//四个方向
{
node next=temp;
next.chess[i].x+=dir[j][0];
next.chess[i].y+=dir[j][1];

if(!next.check(i))//重叠或者越界
{
next.chess[i].x+=dir[j][0];//多走一步
next.chess[i].y+=dir[j][1];
if(!next.check(i))//重叠或者越界
continue;
}

int hash2=gethash(next);// next的hash
it2=mm.find(hash2);


if(it2==mm.end())//不存在
{
mm[hash2]=it1->second+1;//步数+1
que.push(next);
}
else if(it2->second/10==1-flag)//存在 s/10=0走到1结束 e=1走到0结束
{
return true;
}

}
}
}
return false;
}

int main()
{
int i;
while(scanf("%d",&s.chess[0].x)!=EOF)
{
scanf("%d",&s.chess[0].y);
for(i=1;i<4;i++)
scanf("%d%d",&s.chess[i].x,&s.chess[i].y);
for(i=0;i<4;i++)
scanf("%d%d",&e.chess[i].x,&e.chess[i].y);
for(i=0;i<4;i++)
{
s.chess[i].x--;s.chess[i].y--;
e.chess[i].x--;e.chess[i].y--;
}

mm[gethash(s)]=10*0+0;//hash存储 map映射表示对应的s ,步数
mm[gethash(e)]=10*1+0;//s是0 e是1

if(BFS(s,0)||BFS(e,1))
printf("YES\n");
else
printf("NO\n");
mm.clear();
}
}