您的位置:首页 > 其它

位运算状态压缩——飞行员兄弟的冰箱

2016-02-19 17:07 183 查看
nkoj 2223
Description
有一个叫“飞行员兄弟的冰箱”的著名智力游戏,在游戏中玩家需要打开一个冰箱。 

在冰箱的门上有16个门把手,每个门把手只有两种状态:打开和关闭。当所有门把手都处于打开状态时,冰箱才会被打开。 

16个门把手构成了一个4x4的矩阵,当你改变坐标为(x,y)的门把手的状态时,跟它同处于x行和跟它同处于y列的门把手们的状态都同时会被改变(开的变为关,关的变为开)。 

问最少转动几次把手就可以打开冰箱门? 

Input
输入一个有"+"和"-"构成的4x4的矩阵,"+"表示该把手处于关闭状态,"-"表示该把手处于打开状态。
Output
一个整数,表示最小步数 

如果无解,输出"NO"
Sample Input

-+--
----
----
-+--


Sample Output

6

分析:基本思路当然是BFS但是存在以下问题:
1.怎样存储状态?

2.怎样判定是否达到目标或者该状态已经搜索过?

利用位运算,每一个二进制位代表一个开关。那么所有状态都对应着一个0~2^16-1之间的一个整数。

vis[i]表示该状态是否被搜索过

代码如下:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int start=0;
bool vis[66666];
struct node{
int s,step;
node (int a,int b){
this -> s = a ;
this -> step = b ;
}
};
queue <node> q;
int convert(int cur,int x){
int i,y = x;
while(y%4!=0)y--;
for(i=0;i<4;i++)  //同一行
cur ^= (1<<(y+i));
y=x;
while(x>=4)x-=4;  //同一列
for(;x<16;x+=4)
cur ^= (1<<(x));
cur ^= (1<<(y));  //自身被行、列各异或了一次,没有改变
return cur;
}
void input(){
int i=0;
while(i<16){
char ch=getchar();
if(ch=='+'||ch=='-'){
if(ch=='+')start |= (1 << i) ;
i++ ;
}
}
}
bool BFS(){
q.push(node (start,0));
vis[start]=true;
if(!start){
cout<<"0";
return true;
}
while(!q.empty()){
node t=q.front();
q.pop();
for(int i=0;i<16;i++){  //改变每一位
int cur=convert(t.s,i);
if(!cur){  //找到解
cout<<t.step+1;
return true;
}
if(!vis[cur]){   	//	没有被搜索过
q.push(node (cur,t.step+1));
vis[cur]=true;
}
}
}
return false;
}
int main(){
input();
if(!BFS()) cout<<"No";
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: