Flip Game
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 51056 | Accepted: 21551 |
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:
- 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 题意:给了你一个4*4的棋盘,棋盘上的每一个格子里都有一颗一面黑一面白的棋子,一开始给出你棋盘的初始状态,你可以给任何一个棋子翻面,但是如果你翻了某一个棋子,那他上下左右的棋子都要翻面。问你最少需要翻多少次才能让16枚棋子都为黑或都为白。
思路:总共有16个棋子,每个棋子只有两种状态,翻或者不翻,因为一面棋子只有两种颜色,翻基数次等同于只翻了1次,翻偶数次等同于没翻。所以可以分别枚举翻1枚,2枚,3枚,4枚......16枚的所有情况。根据排列组合,枚举完所有情况需要2^16次。那如何进行枚举呢?可以用for循环一 一枚举某一次需要翻的棋子数,然后用DFS搜索翻这个数量的棋子的所有情况。如何DFS呢?首先选择要翻的第一个棋子,然后下一个要翻的棋子从已选择的这个棋子之后进行选择,一直到选完需要数量的棋子,然后判断所有棋子是否为同一种颜色,如果是,则不用再进行搜索了,这就是答案,因为你是从1-16依次枚举,所以第一次满足条件的情况一定是次数最少的;如果不是则继续搜索。具体看代码和注释理解:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std; int visit[];
int map[][];
int ans; void Flip()
{
int x,y;
for(int i=; i<=; ++i)
{
if(visit[i]) //如果标记为 1,表示这个棋子要翻
{
x = i/ + ; // 计算出棋子再棋盘中的位置
y = i % ;
if(i% == )
{
x--;
y = ;
}
map[x][y] = -map[x][y]; //翻自己
map[x-][y] = -map[x-][y]; //翻上
map[x+][y] = -map[x+][y]; //翻下
map[x][y+] = -map[x][y+]; //翻左
map[x][y-] = -map[x][y-]; //翻右
}
}
return;
} int Judge() //判断是否为同一种颜色
{
for(int i=; i<=; ++i)
for(int j=; j<=; ++j)
{
if(map[i][j] != map[][])
return ;
}
return ;
} void DFS(int num,int times,int who) //num表示总共要翻几个琪,times表示已经翻了几个,who表示上一次翻的是哪一个棋
{
if(ans < inf) return; //如果已经找到答案了,就不用往下了
if(times == num) //当翻棋的数量达到了,就进行判断
{
Flip(); //翻棋
if(Judge()) //判断全为同一种颜色
{
ans = num; //记录答案
}
else Flip(); //否则将棋盘恢复原状
return;
} for(int i=who+; i<=; ++i) //从上一个翻的棋子的下一个开始选择,这样可以防止出现重复的情况
{
visit[i] = ;//选中的标记为 1
DFS(num,times+,i); //搜索翻下一个的情况,
visit[i] = ; //清除标记
}
} int main()
{
char first;
memset(map,,sizeof(map));
for(int i=; i<=; ++i)
for(int j=; j<=; ++j)
{
cin>>first;//依次输入棋子
if(first == 'w')
map[i][j] = ; //若为白棋,记为 1
else map[i][j] = -; //黑记为为 -1
} ans = inf; //初始化答案为无穷大
for(int i=; i<=; ++i) //枚举翻棋子数
{
memset(visit,,sizeof(visit)); //每种情况开始前要将标记数组初始化为 0
DFS(i,,); //搜索翻这么多棋子的所有情况
if(ans < inf) break; //如果答案不为无穷大,表示已经有结果了,不用搜了
} if(ans == inf) cout<<"Impossible"<<endl;
else cout<<ans<<endl;
return ;
}