定义
状态压缩,实际上是将一个30左右长度的bool数组用一个int来表示。为什么呢?众所周知,bool类型只有0,1两种两种类型。而计算机又是用二进制来存储数字,加之强大的位运算功能,我们便可以更改整数在二进制下表示的每一位的数字,来表示不同的状态。由于其与位运算密切相关,所以我们先来讨论一下位运算的事情。
位运算
不做演示,可以自行演示验证
S是原集合
S&(1<<(k-1)) 取出第k位
^ 将第k位取反
| 将第k位强制变1
S^(1<<k-1) 取补集
S&(-S) 取出右起第一个1 ,减掉这个结果数就更新状态 lowbit
S|A==S A是S的子集
for(x=s;x;s&(x-1) 枚举子集
题目中的ShowTime
开关游戏
何以状态压缩?唯开关亮灭与否也!
开关矩阵是4*4,所以状态数只有16个,完全可以状态压缩
然后通过宽搜枚举每个按键,注意通过位运算判断边界情况。
一定要记得先判断是否初始状态已经全部亮起或全部熄灭。
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN=65536;
int start;
int Pow[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,8192,16384};
bool Appear[MAXN];
int step[MAXN];
queue<int> Q;
int ans;
int click(int h,int i){
h^=(1<<i);
if((i)%4!=0){
h^=(1<<(i-1));
}
if((i+1)%4!=0){
h^=(1<<(i+1));
}
if(i>=4){
h^=(1<<(i-4));
}
if(i<=11){
h^=(1<<(i+4));
}
return h;
}
int bfs(){
Q.push(start);
step[start]=0;
Appear[start]=true;
while(!Q.empty()){
int h=Q.front();
Q.pop();
for(int i=0;i<=15;i++){
int st=click(h,i);
if(!Appear[st]){
if(st==0||st==65535){
return step[h]+1;
}
Appear[st]=true;
Q.push(st);
step[st]=step[h]+1;
}
}
}
cout<<"Impossible";
return 0;
}
int main(){
// int p=16;
// while(p>0){
// char ch=getchar();
// if(ch=='w'||ch=='b'){
// if(ch=='w')start+=(1<<(p-1));
// p--;
// }
// }
for(int i=15;i>=0;i--){
char ch=getchar();
if(ch=='w'||ch=='b'){
if(ch=='w')start+=(1<<(i));
}
else{
i++;
}
}
if(start==65535||start==0){
cout<<0;
return 0;
}
ans=bfs();
if(!ans){
//cout<<"Impossible";
}
else{
cout<<ans;
}
}