定义
状态压缩,实际上是将一个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; } }