[BZOJ 1054][HAOI 2008]移动玩具 状态压缩

来源:互联网 发布:centos 桥接模式 编辑:程序博客网 时间:2024/05/17 03:59

考试的时候一看是河南省选题,觉得会很难,有点不敢想正解。感觉是个状压。但是一看是十年前的题,那怂什么!

直接把十六个数的状态压进去,因为个数是不变的,所以状态枚举的时候只要找数目一样的转移即可。而且只需找这一位为1的转移即可。因为个数不变,所以转移0到1和转移1到0是一样的。

就是简单的模拟转移,找它的上下左右对应的那一位是否为0,如果是,那么就是从此为是0,那一位是1转移过来的,取个min即可。

因为枚举是暴力枚举,而不是按状态顺序枚举,所以可能在一次枚举的时候有的状态没有转移到,那就重复处理此过程,直到都转移到即可。

比较暴力。能过就行。hhh。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define pos(i,a,b) for(int i=(a);i<=(b);i++)#define pos2(i,a,b) for(int i=(a);i>=(b);i--)int f[1<<16];int count(int x){int sum=0;while(x){if(x&1)  sum++;x>>=1;}return sum;}int tmp,cnt,ans;int flag[20];int main(){freopen("movea.in","r",stdin);freopen("movea.out","w",stdout);memset(f,0x7f,sizeof(f));//cout<<(7^2)<<endl;pos(i,1,16){  char x;  cin>>x;  int xx=x-'0';  if(xx==1)  {tmp|=(1<<((17-i)-1));flag[i]=1;}}pos(i,1,16){  char x;  cin>>x;  int xx=x-'0';  if(xx==1)ans|=(1<<((17-i)-1));}cnt=count(tmp);f[tmp]=0;while(f[ans]>10000000){pos(i,0,(1<<16)-1){if(count(i)==cnt){pos(j,1,16){int qian=(1<<((17-j)-1));if(qian&i){if(((j%4)!=1)&&((1<<((18-j)-1))&i)==0){int temp;temp=(1<<((18-j)-1))|i;temp^=qian;f[i]=min(f[i],f[temp]+1);}if((j%4)&&((1<<((16-j)-1))&i)==0){int temp;temp=(1<<((16-j)-1))|i;temp^=qian;f[i]=min(f[i],f[temp]+1);}if(j<=12&&((1<<((13-j)-1))&i)==0){int temp;temp=(1<<((13-j)-1))|i;temp^=qian;f[i]=min(f[i],f[temp]+1);}if(j>=5&&(((1<<(21-j)-1))&i)==0){int temp;temp=(1<<((21-j)-1))|i;temp^=qian;f[i]=min(f[i],f[temp]+1);}}}}}}cout<<f[ans];//while(1);return 0;}