https://www.luogu.org/problem/P1225
题目描述
黑白棋游戏的棋盘由4×4方格阵列构成。棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子。这16枚棋子的每一种放置方案都构成一个游戏状态。在棋盘上拥有1条公共边的2个方格称为相邻方格。一个方格最多可有4个相邻方格。在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置。对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列。
输入格式
输入文件共有8行。前四行是初始游戏状态,后四行是目标游戏状态。每行4个数分别表示该行放置的棋子颜色。“0”表示白棋;“1”表示黑棋。
输出格式
输出文件的第一行是着棋步数n。接下来n行,每行4个数分别表示该步交换棋子的两个相邻方格的位置。例如,abcd表示将棋盘上(a,b)处的棋子与(c,d)处的棋子换位。
4*4的矩阵相当于16位的01串,明显用二进制状态压缩,2<<16不超过65535
bfs,矩阵转二进制与二进制转矩阵注意一点
为了输出的答案,需要每个状态记录父状态,转移方法的四位数
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define ri register int #define u int using std::string; using std::cin; using std::pow; namespace all { u st,ed; u q[1000001],fa[65555],n[65555],ans[65555]; u _a[5][5]; void dfs(const u &x) { if(!fa[x]) { return; } dfs(fa[x]); printf("%d ",ans[x]); } u make() { u _re(0); for(ri i(1); i<=4; ++i) { for(ri j(1); j<=4; ++j) { _re=(_re<<1)+_a[i][j]; } } return _re; } void bfs() { u l(0),r(0); q[++r]=st; ans[st]=1; while(l+1<=r) { u _x(q[++l]); if(_x==ed) { printf("%d ",n[_x]); dfs(_x); exit(0); } u rest(_x); for(ri i(1); i<=4; ++i) { for(ri j(1); j<=4; ++j) { if(pow(2,(4-i)*4+(4-j))<=rest) { _a[i][j]=1; rest-=pow(2,(4-i)*4+(4-j)); } else _a[i][j]=0; } } for(ri i(1); i<=4; ++i) { for(ri j(1); j<=4; ++j) { if(i+1<=4) { std::swap(_a[i+1][j],_a[i][j]); u _y(make()); if(!ans[_y]) { q[++r]=_y; n[_y]=n[_x]+1; fa[_y]=_x; ans[_y]=i*1000+j*100+(i+1)*10+j; } std::swap(_a[i+1][j],_a[i][j]); } if(j+1<=4) { std::swap(_a[i][j+1],_a[i][j]); u _y(make()); if(!ans[_y]) { q[++r]=_y; n[_y]=n[_x]+1; fa[_y]=_x; ans[_y]=i*1000+j*100+i*10+j+1; } std::swap(_a[i][j+1],_a[i][j]); } } } } } inline void solve() { string _s; for(ri i(1); i<=4; ++i) { cin>>_s; for(ri j(0); j<=3; ++j) { st=(st<<1)+_s[j]-'0'; } } for(ri i(1); i<=4; ++i) { cin>>_s; for(ri j(0); j<=3; ++j) { ed=(ed<<1)+_s[j]-'0'; } } bfs(); } } int main() { //freopen("x.txt","r",stdin); all::solve(); }