在一个4*4的棋盘上有8个黑棋和8个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的。移动棋子的规则是交换相邻两个棋子。如今给出一个初始棋盘和一个最终棋盘,要求你找出一个最短的移动序列使初始棋盘变为最终棋盘。
Klux说:“这么简单的题目,我都会作!”ios
第1到4行每行四个数字(1或者0),描述了初始棋盘
接着是一个空行
第6到9行每行四个数字,描述了最终棋盘框架
输出只有一行是一个整数n,表示最少的移动步数。spa
输入样例#1:
1111
0000
1110
0010code
1010
0101
1010
0101ci
输出样例#1:io
4stream
BFS+位运算。
因为要求最小步数能够看出BFS的基本框架,可是若是用矩阵存储状态的话太耗费空间并且很慢,注意到每一个格子的状态非0即1并且总格子数目为16因此能够用二进制的方法存储状态,相应判断,转移,判重。
注意这里面将棋盘转换成二进制序列的时候,如何计算序列上的值在原4*4棋盘上的位置,以及使用异或运算去生成相邻格子交换后的新棋盘状态对应的二进制序列也是本题特点。
最后,因为是交换相邻的格子,理论上格子和上下左右四个方向均可以互换,可是显然对于每一个格子这样枚举互换存在大量的重复,本质上对于每一个格子从上至下、从左到右只须要让他往右和往下和相邻的格子尝试互换便可。二进制
#include<iostream> #include<queue> #define FOR(a,b,c) for(int a=(b);a<(c);a++) 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(); }