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();
}