棋盘

Description

在一个 4 × 4 4×4 4×4的棋盘上有8个黑棋和8个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的。
移动棋子的规则是交换相邻两个棋子。
给出一个初始棋盘和一个最终棋盘,请找出一个最短的移动序列使初始棋盘变为最终棋盘。

Input

前四行,每行4个数字(1或者0),描述了初始棋盘;
接着是一个空行;
第六到第九行,每行4个数字(1或者0),描述了最终棋盘。

Output

输出一行一个整数表示最少步数。

  • 前置技能 :二进制基本操作、bfs
  • 因为棋盘由01表示,那么我们将原有棋盘转成一串16位二进制数。则原题可抽象为将一个数 A A A转化成另一个数 B B B,求A转到B最少次数显然可以用BFS + 二进制去暴力,
  • 交换的规则我们也可以做优化,只需确定两个方向即可(左、上)或者(右下),这样便不会引起多余的交换
#include
#include
#include
#define maxn 200005
#define INF 0x3f3f3f3f
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:棋盘
struct node{int num,time;};
bool vis[1<<20];
void read(int& num)
{
	int t;
	for(int i=3; i>=0; i--) 
	{
       	cin >>t;
       	for(int j = 3; j>=0; j--)
       	{
       		int k = t%10;
       		t/=10;
       		if(k)num+= 1<<(i*4+j);
		}
    }
}


int bfs(int st,int end)
{
	node st1;
	st1.num = st, st1.time = 0;
	queue<node> q;
	q.push(st1);
	while(!q.empty())
	{
		
		node now = q.front();
		q.pop();
		int num = now.num;
		if(num == end)return now.time;
		for(int i = 0; i<16; i++) //左走 
		{
			int x = (15-i)%4, y = (15-i)/4;	//编号转坐标
			int k = 1<<i,k1 = 1<<(i+1);		//k为当前点  ,k1为交换点
			if(x>0 && (num&k)!=(num&k1))
			{
				if(!vis[num^k^k1])
				{
					vis[num^k^k1] = 1;
					node t_node;
					t_node.num = num^k^k1;
					t_node.time = now.time+1;
					q.push(t_node);
				}
			}
		}
		
		for(int i = 0; i<16; i++) //上走 
		{
			int x = (15-i)%4, y = (15-i)/4;
			int k = 1<<i,k1 = 1<<(i+4);		//k为当前点  ,k1为交换点
			if(y>0 && (num&k)!=(num&k1))
			{
				if(!vis[num^k^k1])
				{
					vis[num^k^k1] = 1;
					node t_node;
					t_node.num = num^k^k1;
					t_node.time = now.time+1;
					q.push(t_node);
				}
			}
		}
	}	
} 


int main()
{
	int st = 0, end = 0, temp;
	read(st); read(end);
	cout << bfs(st,end)<<endl;

	return 0;
}

你可能感兴趣的:(算法)