1451:棋盘游戏
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 394 通过数: 236
【题目描述】
在一个 4×4 的棋盘上有8 个黑棋和 8 个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的。移动棋子的规则是交换相邻两个棋子。
给出一个初始棋盘和一个最终棋盘,请找出一个最短的移动序列使初始棋盘变为最终棋盘。
【输入】
前四行,每行 4 个数字(1 或者 0),描述了初始棋盘;
接着是一个空行;
第六到第九行,每行 4 个数字(1 或者 0),描述了最终棋盘。
【输出】
一行是一个整数 n,表示最少的移动步数。
【输入样例】
1111
0000
1110
0010
1010
0101
1010
0101
【输出样例】
4
思路:本题主要考察BFS+位运算,4*4棋盘上的位置,使用异或运算去生成相邻格子交换后的新棋盘状态对应的二进制序列。由于是交换相邻的格子,理论上格子和上下左右四个方向都可以互换,但是显然对于每个格子这样枚举互换存在大量的重复,本质上对于每个格子从上至下、从左到右只需要让他往右和往下和相邻的格子尝试互换即可。
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int maxn = 16;
struct Node{ // 结构体存棋盘的二进制序列和步数
int num,d;
};
int A,B;
int vis[100000];
void BFS() {
queue<Node> q;
q.push((Node){A,0});
while(!q.empty())
{
Node u = q.front(); q.pop();
int tmp = u.num;
if(tmp == B) { cout<<u.d; return ; }
for(int i = 15;i >= 0;i--) // 棋盘对应的二进制序列,从高到低依次枚举每个位置
{
int x = (15-i)/4,y = (15-i)%4,w = 1<<i,z; //计算该位置在棋盘上的x和y座标值
if(y<3 && (tmp&(1<<i)) != (tmp&(1<<i-1))) //向右交换,二进制序列的i和i-1交换
{
z = 1<<i-1;
if(!vis[tmp^z^w]) {
vis[tmp^z^w] = 1;
q.push((Node){tmp^z^w,u.d+1});
}
}
if(x<3 && (tmp&(1<<i)) != (tmp&(1<<i-4))) //向下交换,二进制序列的i和i-4交换
{
z = 1<<i-4;
if(!vis[tmp^z^w]) {
vis[tmp^z^w] = 1;
q.push((Node){tmp^z^w,u.d+1});
}
}
}
}
}
int main()
{
char c;
for(int i = 15;i >= 0;i--) {
cin>>c;
if(c != '0') A += 1<<i;
}
for(int i=15;i>=0;i--) {
cin>>c;
if(c != '0') B += 1<<i;
}
if(A == B) cout<<0;
else BFS();
}