poj1753 位压缩+bfs
2014-03-26 18:39
316 查看
题目大意:有一个4*4的方格,每个方格中放一粒棋子,这个棋子一面是白色,一面是黑色。游戏规则为每次任选16颗中的一颗,把选中的这颗以及它四周的棋子一并反过来,当所有的棋子都是同一个颜色朝上时,游戏就完成了。现在给定一个初始状态,要求输出能够完成游戏所需翻转的最小次数,如果初始状态已经达到要求输出0。如果不可能完成游戏,输出Impossible。
主要思想:
1、如果用一个4*4的数组存储每一种状态,不但存储空间很大,而且在穷举状态时也不方便记录。因为每一颗棋子都只有两种状态,所以可以用二进制0和1表示每一个棋子的状态,则棋盘的状态就可以用一个16位的整数唯一标识。而翻转的操作也可以通过通过位操作来完成。显然当棋盘状态id为0(全白)或65535(全黑)时,游戏结束。
2、对于棋盘的每一个状态,都有十六种操作,首先要判断这十六种操作之后是否有完成的情况,如果没有,则再对这十六种操作的结果分别再进行上述操作,显然这里就要用到队列来存储了。而且在翻转的过程中有可能会回到之前的某种状态,而这种重复的状态是不应该再次入队的,所以维护 Visit[i]数组来判断 id==i 的状态之前是否已经出现过,如果不是才将其入队。如果游戏无法完成,状态必定会形成循环,由于重复状态不会再次入队,所以最后的队列一定会是空队列。
3、由于0^1=1,1^1=0,所以翻转的操作可以通过异或操作来完成,而翻转的位置可以通过移位来确定。
主要思想:
1、如果用一个4*4的数组存储每一种状态,不但存储空间很大,而且在穷举状态时也不方便记录。因为每一颗棋子都只有两种状态,所以可以用二进制0和1表示每一个棋子的状态,则棋盘的状态就可以用一个16位的整数唯一标识。而翻转的操作也可以通过通过位操作来完成。显然当棋盘状态id为0(全白)或65535(全黑)时,游戏结束。
2、对于棋盘的每一个状态,都有十六种操作,首先要判断这十六种操作之后是否有完成的情况,如果没有,则再对这十六种操作的结果分别再进行上述操作,显然这里就要用到队列来存储了。而且在翻转的过程中有可能会回到之前的某种状态,而这种重复的状态是不应该再次入队的,所以维护 Visit[i]数组来判断 id==i 的状态之前是否已经出现过,如果不是才将其入队。如果游戏无法完成,状态必定会形成循环,由于重复状态不会再次入队,所以最后的队列一定会是空队列。
3、由于0^1=1,1^1=0,所以翻转的操作可以通过异或操作来完成,而翻转的位置可以通过移位来确定。
#include<iostream> #include<queue> #include<cstdio> using namespace std; #include<memory.h> struct Node { int state; int step; }; bool visit[65536]; int change[16] = //16种状态转换,对应4*4的翻子位置 { 51200,58368,29184,12544, 35968,20032,10016,4880, 2248,1252,626,305, 140,78,39,19 }; int bfs(int state) { int i; memset(visit,false,sizeof(visit)); //标记每一个状态都未访问过 queue<Node>q; Node cur,next; cur.state = state; cur.step = 0; q.push(cur); visit[state] = true; while(!q.empty()) { cur = q.front(); q.pop(); if(cur.state == 0 || cur.state == 0xffff) //65535 return cur.step; for(i=0;i<16;i++) { next.state = cur.state^change[i]; next.step = cur.step + 1; if(visit[next.state]) continue; if(next.state == 0 || next.state == 0xffff) //65535 return next.step; visit[next.state] = true; q.push(next); } } return -1; } int main(void) { int i,j,state,ans; char ch[5][5]; while(scanf("%s",ch[0])!=EOF) { for(i = 1 ; i < 4 ; ++i) scanf("%s",ch[i]); state = 0; for(i = 0 ; i < 4 ; ++i) { for(j = 0 ; j < 4 ; ++j) { state <<= 1; if(ch[i][j] == 'b') state += 1; //state ^= (1<<((3-i)*4+(3-j))); } } ans = bfs(state); if(ans == -1) puts("Impossible"); else printf("%d\n",ans); } return 0; }
相关文章推荐
- 9.7 Region(部分)
- iOS 按钮拖动。
- Day3 - bind 显示或设置按键的组合
- 说说PHP是什么格式 要怎么打开
- 优酷土豆2012.9.12校园招聘笔试题
- Oracle 分区表
- 进程与I/O
- 自定义android的tab样式
- 关于oc中内存管理问题
- 比较 PHP集成开发工具(IDE)
- 找出数组中两个只出现一次的数字
- zoj 3626 Treasure Hunt I(树背包)
- 活用UML-软件设计高手(深圳 2014年4月26-27日)
- poj 3228 Gold Transportation
- Leetcode--Search in Rotated Sorted Array(旋转数组的查找)
- Tomcat 6.x 生成CSR
- 第三周作业——顺序查找和二分查找
- 对android的一些感想——2014-03-26
- 阶层之和
- 【每周荐书05】《新亚遗铎》(钱穆 著)