題解0008:棋盤遊戲
阿新 • • 發佈:2022-04-10
題目連結:http://ybt.ssoier.cn:8088/problem_show.php?pid=1451
(信奧一本通1451)
題目描述:輸入倆棋盤(4*4),一半黑子(1)一半白子(0),兩個棋子可以交換,問第一個棋盤要交換多少次才能變成第二個。
題目思路:
廣搜,先找出兩個棋盤的不同,再兩兩交換,最後求出步數
但是要是用2維陣列模擬的話肯定超時,所以我們要優化一下
我們可以用位運算,將棋盤轉成一串2進位制數,再轉化成10進位制存起來
這樣就只用判斷兩個陣列了,大大縮短時間
(具體詳見程式碼註釋)
#include<bits/stdc++.h>
using namespace std;
struct Q{
int a,b;
};//存在佇列裡的結構體,a是二進位制狀態的當前棋盤,b是步數
int A,B,arr[1000000]={0};//判斷一個位置是否交換過
void bfs(){
queue<Q> q;
q.push((Q){A,0});//將初始棋盤塞入佇列,清零步數
while(!q.empty()){
Q u=q.front();
q.pop();
int temp=u.a;
if(temp==B){//如果交換後的棋盤與最終棋盤重合證明找到了,輸出結束
cout<<u.b;
return;
}
for(int i=15;i>=0;i--){
int x=(15-i)%4;
int y=(15-i)/4;
//找棋盤某位置在陣列狀態的x和y座標
int z=(1<<i);
int r;
if(x<3&&(temp&(1<<i))!=(temp&(1<<i-1))){//判斷左右能不能換
//(x>3是為了不讓第一排最後一個和第二排第一個交換)
r=(1<<i-1);
if(arr[temp^z^r]==0){//判斷有沒有交換過
arr[temp^z^r]=1;
q.push((Q){temp^z^r,u.b+1});//交換棋盤,步數+1
}
}
if(y<3&&(temp&(1<<i))!=(temp&(1<<i-4))){//判斷左右能不能換(上下差4個)
r=(1<<i-4);
if(arr[temp^z^r]==0){//判斷有沒有交換過
arr[temp^z^r]=1;
q.push((Q){temp^z^r,u.b+1});//交換棋盤,步數+1
}
}
}
}
}
int main(){
char p;//要一個一個單數存,所以用char
int i;
for(i=15;i>=0;i--){
cin>>p;
A+=(p-'0')*1<<i;//用十進位制表示二進位制數存棋盤
}