题目: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;
}
总结:做这题需要有强大的知识储备
做不出来的建议重修位运算
浙公网安备 33010602011771号