题解0008:棋盘游戏
题目链接://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;//用十进制表示二进制数存棋盘
}
for(i=15