现在的位置: 首页 > 综合 > 正文

HDU 1401 Solitaire 双向BFS

2018年01月19日 ⁄ 综合 ⁄ 共 3448字 ⁄ 字号 评论关闭

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).

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();
	}
} 

抱歉!评论已关闭.