1. 程式人生 > 其它 >012(棋盤遊戲)

012(棋盤遊戲)

題目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1451

題目簡述:有兩個4*4的黑白棋盤,每一個棋子可以與它上下左右的棋子交換

求第一個棋盤最少經過幾次變到第二個棋盤

思路:“最少”,毫無疑問,bfs。

這邊用佇列儲存每個分支棋盤以及用最初棋盤做出此分支所用的步數

因此,我們的佇列會是一個結構體佇列

然後就是去去分支

由於某一個棋子向左向下換位後得到的棋盤已經是這個棋盤的上一個棋盤

所以只需要考慮向下向右換位的即可

然後就是儲存

佇列裡面是不可能存一個數組的

所以我們考慮用二進位制的寫法來存

而換位就靠異或

上程式碼

#include<bits/stdc++.h>
using namespace std;
int i,s1,s2;char c;
//由於輸入格式的侷限性,輸入這個棋盤用char 
struct yfwguigdyweiugh{
	int sum,t;
};//sum是當前棋盤,t是用最初棋盤做出此分支所用的步數 
bool v[100000];
int bfs(){
	yfwguigdyweiugh a,b;
	queue<yfwguigdyweiugh> q;
	a.sum=s1;
	a.t=0;
	q.push(a);
	//上文全是初始化 
	while(!q.empty()){//如果還有的搜 
		a=q.front();//把最前面那個分支拿出來 
		q.pop();
		if(a.sum==s2){//棋盤重合了意味著找到了 
			return a.t;//直接回溯 
		}
		int l=a.sum;
		for(int i=15;i>=0;i--){
			b=a;
			int x=(15-i)%4;
			int y=(15-i)/4;
			//找到這個棋子在棋盤中的橫縱座標 
			int z,o=(1<<i);
			if(x<3&&(l&(1<<i))!=(l&(1<<i-1))){//左右能換 
				z=1<<(i-1);
				if(!v[l^o^z]){//就用異或換 
					v[l^o^z]=true;
					b.sum=l^o^z;
					b.t++;
					q.push(b);//存下來 
					b.t--;//記得回溯 
				}
			}
			if(y<3&&(l&(1<<i))!=(l&(1<<i-4))){//上下能換 
				z=1<<(i-4);
				if(!v[l^o^z]){//就用異或換
					v[l^o^z]=true;
					b.sum=l^o^z;
					b.t++;
					q.push(b);//存進來 
					//本次無需回溯 
				}
			}
		}
	}
}
int main(){
	memset(v,false,sizeof(v));
	for(i=15;i>=0;i--){
		cin>>c;
		if(c=='1'){
			s1+=1<<i;
		}
	}
	for(i=15;i>=0;i--){
		cin>>c;
		if(c=='1'){
			s2+=1<<i;
		}
	}
	printf("%d",bfs());
	return 0;
}

總結:做這題需要有強大的知識儲備

做不出來的建議重修位運算