首页 > 代码库 > POJ1753:Flip Game
POJ1753:Flip Game
Flip Game
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 29713 | Accepted: 12876 |
Description
Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it‘s black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:
Consider the following position as an example:
bwbw
wwww
bbwb
bwwb
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:
bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.
- Choose any one of the 16 pieces.
- Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).
Consider the following position as an example:
bwbw
wwww
bbwb
bwwb
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:
bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.
Input
The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.
Output
Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it‘s impossible to achieve the goal, then write the word "Impossible" (without quotes).
Sample Input
bwwb bbwb bwwb bwww
Sample Output
4
<pre name="code" class="cpp"> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; bool chess[6][6]={false};//利用的只有中心的4x4 bool flag; int step; int x[]={-1,1,0,0,0};//用于翻棋操作 int y[]={0,0,-1,1,0}; bool all()//判断是否是全黑或全白 { for(int i=1; i<=4; i++) for(int j=1; j<=4; j++) if(chess[i][j]!=chess[1][1]) return false; return true; } void flip(int m,int n)//翻棋 { for(int i=0; i<=4; i++) chess[m+x[i]][n+y[i]]=!chess[m+x[i]][n+y[i]]; return; } void dfs(int m,int n,int deep) { if(deep==step) { flag=all(); return; } if(flag||m==5)return; flip(m,n); //翻棋 if(n<4) dfs(m,n+1,deep+1); else dfs(m+1,1,deep+1); flip(m,n); //不符合话就翻回来 if(n<4) dfs(m,n+1,deep); else dfs(m+1,1,deep); return; } int main() { char str; for(int i=1; i<=4; i++) for(int j=1; j<=4; j++) { cin>>str; if(str=='b') chess[i][j]=true; } for(step=0;step<=16;step++) //对每一步产生的可能性进行枚举 { //考虑到4x4=16格,而每一格只有黑白两种情况,则全部的可能性为2^16 dfs(1,1,0); if(flag)break; } if(flag) cout<<step<<endl; else cout<<"Impossible"<<endl; return 0; }
还有些大神是用位运算写的,由于不会,所以也就直接复制过来作为学习参考。
//把矩阵看成一个16进制数 //每一行代表16进制数的一个字母(或数字),而每一个字母(或数字)又恰由4个二进制位数字0和1组成 //因此一个4x4矩阵是由16位0和1构成,是从 第0位 到 第15位 //如矩阵 // * * * * 从右到左分别为第 0, 1, 2, 3位 // % % % % 从右到左分别为第 4, 5, 6, 7位 // # # # # 从右到左分别为第 8, 9,10,11位 // @ @ @ @ 从右到左分别为第12,13,14,15位 //代表16进制数 // @@@@ #### %%%% **** // 15 ← 0 // 将一个int的某位 取反 用该int与(0x1<<i)进行^操作。 #include<iostream> struct unit { int x; //用int的末16位记录16个位置的信息 int rounds; //记录第几轮达到当前的状态 int i; //记录该状态是通过翻动哪个棋子得来的,以避免返回先前的状态 }; //flip函数是从a状态通过翻动第i个棋子到达b状态 void flip(unit a, int i, unit& b) //a是queue[p]的形参, 当前要翻动第i只棋子, b是queue[q]的引用 { int x = i / 4, y = i % 4; //x、y为当前要翻动的第i只棋子所对应内节点的坐标(就是所翻动棋子的行x列y) b.x = a.x; //即令queue[q].x=queue[p].x ,即q先复制p(前一步)的状态,再对q进行翻转(对p状态无影响) b.x = ((b.x) ^ (0x1 << (i))); //将一个b.x的第i位 取反,其实就是把 第i只棋子 翻转 if (x > 0) b.x = ((b.x) ^ (0x1 << (i - 4))); //把 第i只棋子 上面的棋子翻转,当且仅当棋子i不在第0行时执行 if (x < 3) b.x = ((b.x) ^ (0x1 << (i + 4))); //把 第i只棋子 下面的棋子翻转,当且仅当棋子i不在第3行时执行 if (y > 0) b.x = ((b.x) ^ (0x1 << (i - 1))); //把 第i只棋子 右面的棋子翻转,当且仅当棋子i不在第0列时执行 if (y < 3) b.x = ((b.x) ^ (0x1 << (i + 1))); //把 第i只棋子 左面的棋子翻转,当且仅当棋子i不在第3列时执行 b.rounds = a.rounds + 1; //当前执行翻转棋子的次数 b.i = i; //记录当前翻转的是第i只棋子 return; } int main() { /*queue*/ unit queue[100000]; //queue是一个队列,记录所有状态 queue[0].x = 0; //初始化为16进制的0(16进制的0和10进制的0是一样的) queue[0].i = -1; queue[0].rounds = 0; //judge used bool used[100000]={false}; //used记录已经存在的状态 /*read in*/ char str[10]; for (int i = 0; i < 4; i++) { scanf("%s", str); //一次输入一行字符串str(串长为4),输4次 for (int j = 0; j < 4; j++) if (str[j] == 'b') queue[0].x = ((0x1 << (i * 4 + j)) | (queue[0].x)); //位运算,遇b该位置1 } // 0x1为16进制的1 int p = 0, q = 0; //p,q分别是队列的头尾指针 //其实queue[p].x代表每一步的翻转前状态,queue[q].x代表每一步的翻转后状态 while (!((queue[q].x == 0) || (queue[q].x == 0xFFFF))) //当16进制数queue[q].x 不为0(全0)或15(全1)时执行 { for (int i = 0; i < 16; i++) //最多翻动16只棋子,i代表第i只棋子 { if(queue[p].i==i) //若翻动当前棋子i的前一步所翻的棋子queue[p].i就是i,则跳过不翻动 continue; q++; //尾指针后移一位,为新状态“开辟”新的记录空间 flip(queue[p], i, queue[q]); if (used[queue[q].x]) //以棋盘的状态(一个16进制数)作为数组used的下标,对应的对象为true时说明这个状态已经出现过 q--; //在得到一个新状态的时候要检验之前时候存在这个状态,如果存在就把这个状态舍弃,即q-- //但是下一次循环则继续翻下一只棋子,与状态的舍弃无关,相当于本次所翻的棋子操作无效 else used[queue[q].x]=true; //若该状态没有出现过,则记录该状态 if ((queue[q].x == 0) || (queue[q].x == 0xFFFF))break; //棋盘状态为全0或全1时跳出for,由于while的条件关系,自然也跳出while } if (p==q) //此条件为真时,当且仅当BFS到最后一层的最后一种状态时仍没有匹配的状态(全0或全1) { //简单来说,就是当搜索到最后一层时,程序通过条件结束for,而不是通过break printf("Impossible"); //直至搜索结束,队列queue中都没有目标状态(此时为impossible)。 break; } p++; //头指针后移一位,把当前状态作为初始状态 } if ((queue[q].x == 0) || (queue[q].x == 0xFFFF)) //这是为了隔离因"impossible"时跳出while的情况 printf("%d\n", queue[q].rounds); return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。