Poj_2965 The Pilots Brothers' refrigerator(状态压缩,bfs)
来源:互联网 发布:linux自动登录ssh脚本 编辑:程序博客网 时间:2024/05/18 02:38
题意:
有一个4*4的矩阵,01填充,通过翻转把所有的0变为1,但是翻转[i,j]的同时,要把同行同列的都翻转。
思路:
最开始的时候写了裸的BFS,太过暴力所以果断TLE。看了题解才知道是状态压缩,很高兴能遇到这样经典的状态压缩题目。虽然有巧妙的解法,但是从状态压缩中学到了更多的东西。
首先有几个点要先明白:
1. 每个点最多翻转一次;(翻转2n次相当于没翻转,翻转2n+1次相当于翻转1次)
2. 每个点翻转的顺序无所谓,组合起来的结果相同;
3. unsigned short(16 bits)可以存储一个情况;
4. 最多有2^16=65536种组合情况;
5. 状态的转换可以用位运算完成;
这样我们可以用一个unsigned short型的变量来存储状态,另外用一个结构体数组来存储状态的前驱和变换次数,两个数组都只需要开到65536,这样我们再进行BFS效率就会高很多了。
代码实现:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;const int MAX = 65536;struct Node{ bool exist; int pre; int change; int times;};int pos;int num;Node que[MAX];int dx[16] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4};int dy[16] = {1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4};unsigned short lis[MAX];unsigned short update_pos(unsigned short cur,int type);void check(unsigned short cur);int main(){ char tmp; int cnt = 0; unsigned short initial = 0; for(int i = 0;i < 4; i++ ){ for( int j = 0; j < 4; j++ ){ scanf("%c",&tmp); if( tmp == '-' ){ initial |= (1<<cnt); } cnt++; } getchar(); } for( int i = 0; i < MAX; i++ ){ que[i].change = -1; que[i].exist = false; que[i].pre = -1; que[i].times = 0; } que[initial].exist = true; pos = 0; num = 1; lis[0] = initial; //check(initial); while( pos < num ){ unsigned short cur = lis[pos]; for( int i = 0; i < 16; i++ ){ unsigned short rep = update_pos(cur,i); //check(rep); if( que[rep].exist == true ){ continue; } que[rep].exist = true; que[rep].pre = cur; que[rep].change = i; que[rep].times = que[cur].times+1; lis[num] = rep; num++; //结果可以按任意顺序输出 if( rep == 0xffff ){ printf("%d\n",que[rep].times); while( que[rep].pre != -1 ){ printf("%d %d\n",dx[que[rep].change],dy[que[rep].change]); rep = que[rep].pre; } return 0; } } pos++; } return 0;}unsigned short update_pos(unsigned short cur,int type){ unsigned short mod; switch(type){ case 0: mod = 0x111f;break; case 1: mod = 0x222f;break; case 2: mod = 0x444f;break; case 3: mod = 0x888f;break; case 4: mod = 0x11f1;break; case 5: mod = 0x22f2;break; case 6: mod = 0x44f4;break; case 7: mod = 0x88f8;break; case 8: mod = 0x1f11;break; case 9: mod = 0x2f22;break; case 10: mod = 0x4f44;break; case 11: mod = 0x8f88;break; case 12: mod = 0xf111;break; case 13: mod = 0xf222;break; case 14: mod = 0xf444;break; case 15: mod = 0xf888;break; } return cur^mod;}void check(unsigned short cur){ for( int i = 0; i < 4; i++ ){ for( int j = 0; j < 4; j++ ){ printf("%d ",cur%2); cur /= 2; } printf("\n"); } printf("\n");}
另外的一种巧妙解法,也很好理解:
每一个+都可以通过7次翻转变为-(中间加同行同列每个格子转一次),同时同行同列的其余六个格子(变换4次)不改变,其余格子(变换2次)也不改变。那么我们可以按照这个方法操作每一个关闭的开关'+',想要得到最少就是要去掉不必要的翻转,而不必要的翻转就是那些操作了偶数次的点(因为一个点翻转了偶数次的效果和不翻转效果相同)。之后把那些统计操作次数为奇数次的点按顺序操作一次就好了(因为一个点操作奇数次和操作1次的效果相同,且顺序任意)。
代码实现:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;int res;int cnt[16];int main(){ res = 0; char tmp; memset(cnt,0,sizeof(cnt)); for( int i = 0; i < 16; i++ ){ cin>>tmp; if( tmp == '+' ){ int row = i/4; int column = i%4; cnt[row*4]++; cnt[row*4+1]++; cnt[row*4+2]++; cnt[row*4+3]++; cnt[column]++; cnt[column+4]++; cnt[column+8]++; cnt[column+12]++; cnt[row*4+column]--; } } for( int i = 0; i < 16; i++ ){ if( cnt[i]%2 == 1 ){ res++; } } printf("%d\n",res); for( int i = 0; i < 16; i++ ){ if( cnt[i]%2 == 1 ){ printf("%d %d\n",i/4+1,i%4+1); } } return 0;}
0 0
- Poj_2965 The Pilots Brothers' refrigerator(状态压缩,bfs)
- The Pilots Brothers' refrigerator(POJ_2965)
- The Pilots Brothers' refrigerator(POJ_2965)
- poj_2965 The Pilots Brothers' refrigerator(bfs+位运算)
- BFS + 状态压缩 POJ 2965 The Pilots Brothers' refrigerator
- POJ2965 The Pilots Brothers' refrigerator 「BFS+状态压缩」
- poj 2965 The Pilots Brothers' refrigerator bfs+状态压缩+路径回溯
- The Pilots Brothers' refrigerator(POJ 2965)(dfs枚举+状态压缩)
- poj2965 The Pilots Brothers' refrigerator(枚举,压缩)
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- The Pilots Brothers' refrigerator
- MFC基于对话框的用Picture Control显示OpenGL
- C#Socket编程多客户端基于同一服务端通信
- SSH2整合项目开发中spring配置文件applicationContext.xml分析
- sql语法的查缺补漏(MySQL、SQL Server、Access、Oracle、DB2 等等关系型数据库)
- 如何将HTTP站点转换成HTTPS、及后续问题
- Poj_2965 The Pilots Brothers' refrigerator(状态压缩,bfs)
- inflate 方法与 findViewById方法的区别
- 动力节点——封装(七)
- alignment fault
- maven项目发布到tomcat里lib包没有发布的问题
- ES6和原生js笔记
- C#关闭窗口方式以及线程后台运行
- Linux c编程--利润提成
- nginx监听事件流程