poj 1753(位压缩+搜索)
来源:互联网 发布:java开发平台搭建 编辑:程序博客网 时间:2024/06/05 03:31
题意:有一个4*4的方格,每个方格中放一粒棋子,这个棋子一面是白色,一面是黑色。游戏规则为每次任选16颗中的一颗,把选中的这颗以及它四周的棋子一并反过来,当所有的棋子都是同一个颜色朝上时,游戏就完成了。现在给定一个初始状态,要求输出能够完成游戏所需翻转的最小次数,如果初始状态已经达到要求输出0。如果不可能完成游戏,输出Impossible。
分析:看完这道题,一种很直观的想法就是,对给出的初始状态,由于能进行16种不同的操作(总共16枚棋子),因此就枚举每一种操作后能达到的状态,看是否满足题目要求,若不能就继续进行操作,直到满足题目条件或判断出无法完成为止。
刚开始本以为这样会超时的,毕竟每一个状态都能衍生出16个状态,这样就相当于一个16叉树了。但在网上看了大神的题解后才知道,实际上暴力搜索是能求解的。。。只是如果每次都用一个4*4的数组存储状态,不仅空间开不下,而且处理和记录状态信息也很麻烦,因此要用二进制压缩状态。
1:由于每个棋子都是黑色或白色的,因此,可以用0表示白色,1表示黑色,这样每个棋子就只能处于两种状态之一,而整个棋盘可以用一个16位整数唯一标示。显然,当棋盘表示0(全白)或65535(全黑)时,游戏结束。
2:翻转某个棋子等价于::让表示它的数字异或1,如0^1=1,1^1=0。这样,对棋盘的每次操作就转换为:对标示它的数字按位异或1。例子见代码注释;
3:对每个状态衍生出的16种状态,首先判断其中有没有全黑或全白的,若没有就继续进行衍生。这里很明显用队列存储状态。衍生出的状态依次入队,但已经出现过的状态不应再次入队,因此要用一个标志数组vis[]对出现的状态进行标示。这样,无论是否有解,队列最终都会为空。
/*用0表示白色,1表示黑色,每一个状态都有一个16位数唯一标示:eg: bwwb bbwb bwwb bwww即可表示为1001 1101 1001 1000,其十进制值为40344。对棋盘的每次操作都可以用异或实现。如翻转左上角第一个棋子的话,过程如下: 1001 1101 1001 1000 ^ 1100 1000 0000 0000 = 0101 0101 1001 1000 (翻转后的状态) 翻转第二行第二个棋子的话即为: 1001 1101 1001 1000 ^ 0100 1110 0100 0000 = 1101 0011 1101 1000 (翻转后的状态) ...... 可以看出,翻转左上角第一个棋子时异或的 1100 1000 0000 0000 是由 0000 0000 0000 0000 翻转对应位置所得来的。 翻转第二行第二个棋子时异或的 0100 1110 0100 0000 是由 0000 0000 0000 0000 翻转对应位置所得来的。 ....... 因此,总共有16个数,每个数都代表一个操作。当要执行某个操作时,直接异或对应的数就行了。那么程序中首先就先把这16个数求出来。*/#include<cstdio>#include<cstring>#include<iostream>#include<cstdlib>#include<cmath>#include<algorithm>#include<queue>#include<stack>#include<set>#include<map>using namespace std;typedef pair<int,int> pii;const int M=1010;const int N=100010;int n,m,change[16];int d[4][2]={0,1,0,-1,1,0,-1,0};char s[M][M];bool vis[N];struct node{ int d,step;};void init() // 求出代表操作的16个数,存储在数组change[]里。{ int e=0; for (int i=0;i<4;i++){ for (int j=0;j<4;j++){ int t=0; t^=(1<<((3-i)*4+3-j)); for (int k=0;k<4;k++){ int x=i+d[k][0]; int y=j+d[k][1]; if (x>=0 && x<4 && y>=0 && y<4) { t^=(1<<((3-x)*4+3-y)); } } change[e++]=t; //cout<<t<<endl; } }}int get() // 得到初始棋盘表示的数{ int t=0; for (int i=0;i<4;i++) for (int j=0;j<4;j++) { t<<=1; if (s[i][j]=='b') t|=1; } return t;}int bfs(int temp){ int i,j; node t; memset(vis,false,sizeof(vis)); t.d=temp; t.step=0; queue<node> q; q.push(t); vis[temp]=true; while(!q.empty()) { t=q.front(); q.pop(); if (t.d==0 || t.d==0xffff) return t.step ; for (i=0;i<16;i++) { node r; r.d=t.d^change[i]; r.step=t.step+1; if (vis[r.d]) continue; vis[r.d]=true; if (r.d==0 || r.d==0xffff) return r.step; q.push(r); } } return -1;}int main(){ int i,j,ans; init(); while(~scanf("%s",s[0])) { for (i=1;i<4;i++) scanf("%s",s[i]); int t=get(); if (t==0 || t==0xffff) ans=0; else ans=bfs(t); if (ans==-1) puts("Impossible"); else printf("%d\n",ans); }}
- poj 1753(位压缩+搜索)
- POJ 2411 位压缩dp
- POJ 2443 位压缩加速
- POJ 1753 Flip Game BFS+位压缩状态
- POJ 1753 Flip Game(bfs+状态压缩+位运算)
- POJ 1753 Flip Game(搜索+位运算)
- POJ 2046 Gap 搜索- 状态压缩
- poj 3740 Easy Finding 搜索+位运算
- POJ1753 棋盘翻转(位压缩+广度优先搜索)
- HDU 3006 The Number of set (搜索+位压缩)
- POJ1753 棋盘翻转(位压缩+广度优先搜索)
- POJ1753 Flip Game(搜索,枚举,位运算压缩)
- uva 1601 poj 3523 Morning after holloween 万圣节后的早晨 (经典搜索,双向bfs+预处理优化+状态压缩位运算)
- poj 炮兵阵地 状态压缩DP + 位运算
- poj 2777 Count Color(线段树、状态压缩、位运算)
- 【状态压缩&位运算】poj 2436 Disease Management
- POJ 3628 Bookshelf 2(状态压缩DP+位运算)
- poj 1143 Number Game 博弈 记忆化状态压缩搜索
- mysql搭建以及基本命令
- struct和class的区别
- VC HID开发笔记
- 创建表及设置属性的约束条件
- NYOJ 子串和 44
- poj 1753(位压缩+搜索)
- String,StringBuffer与StringBuilder的区别??
- XmlHttpRequesterror:OriginnullisnotallowedbyAccess-Control-Allow-Origin
- Device Compatibility
- SpringMVC中的观察者模式
- Shell脚本的控制语句
- JNI字段描述符“([Ljava/lang/String;)V”
- Mac 显示隐藏文件
- HDOJ 最大连续子序列 1231