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

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;
}


你可能感兴趣的:(位运算状态压缩——飞行员兄弟的冰箱)