洛谷P1117 棋盘游戏

题意:

在一个 4×4 的棋盘上有 8 个黑棋和 8 个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的。移动棋子的规则是交换相邻两个棋子。给出一个初始棋盘和一个最终棋盘,请找出一个最短的移动序列使初始棋盘变为最终棋盘。
输入
前四行,每行 4 个数字(1 或者 0),描述了初始棋盘;接着是一个空行;第六到第九行,每行 4 个数字(1 或者 0),描述了最终棋盘。

输出
输出文件的第一行是一个整数 n,表示最少的移动步数。

思路:

求最短移动路径加上这种棋盘问题很容易想到要用搜索,但直接用的话判断终止条件为遍历两个图是否相等。。很容易超时,然后我们就要想办法把这个判断简化;
发现输入的棋盘是用0和1来表示的,大小也固定为4*4,所以我们可以用16位二进制来表示这个棋盘,为了方便我们将第一个数作为最高位,以此类推。
因为题目要求是相邻(上下左右)两个棋子交换,所以我们可以从四个顶点任意一个向其对角线方向进行搜索,方便起见,我们从左上角向右下搜索。左右交换、上下交换。
最好自己写一下二进制数,方便理解

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
struct stu
{
	int sum;
	int b;
};
int ans1,ans2;
bool vis[70000];
char ch;
int bfs()
{
	struct stu a,s;
	a.sum=ans1;
	a.b=0;
	queue<stu> q;
	q.push(a);
	while(!q.empty())
	{
		a=q.front();
		q.pop();
		if(a.sum==ans2)
		  return a.b;
		int temp=a.sum;
		for(int i=15;i>=0;i--){
			s=a;
			int x=(15-i)%4,y=(15-i)/4,z,t=1<<i;     //x,y表示当前坐标   
			//printf("%d %d\n",temp&(1<
			if(x<3&&(temp&(1<<i))!=(temp&(1<<i-1)))    //当前数与左右交换后数不一致则存储
			{
				z=1<<(i-1);   
				if(!vis[temp^t^z])    //异或,使两位交换
				{
					vis[temp^t^z]=true;
					s.sum=temp^t^z;
					s.b++;
					q.push(s);
					s.b--;
				}
			}
			//printf("%d %d\n",temp&(1<
			if(y<3&&(temp&(1<<i))!=(temp&(1<<i-4)))   //当前数与上下交换后数不一致则存储
			{
				z=1<<(i-4);
				if(!vis[temp^t^z])
				{
					vis[temp^t^z]=true;
					s.sum=temp^t^z;
					s.b++;
					q.push(s);
				}
			}
		}
	}
}
int main()
{
	memset(vis,false,sizeof(vis));
	for(int i=15;i>=0;i--){
		cin>>ch;
		if(ch=='1')
		  ans1+=1<<i;
	}
//	cout<
	for(int i=15;i>=0;i--){
		cin>>ch;
		if(ch=='1')
		  ans2+=1<<i;
	}
//	cout<
	printf("%d\n",bfs());
	return 0;
}

你可能感兴趣的:(思维,搜索)