题目大意:有一个4×4的棋盘,棋盘上每一点都有黑白两面,每次可以翻转任意一点,在翻转某一点时,该点上下左右的4个临近点同时也会被翻转,现在问你要使棋盘上所有点的颜色统一所需要的最小翻转次数。
分析:其实这道题是典型的高斯消元,不过我是用DFS来做的。
首先我们知道,对于棋盘上任意一点,翻转偶数次是没有意义的,翻转奇数次和翻转一次是一样的,这就意味着,最大的翻转次数也不会超过4×4=16次,这样我们就可以枚举每一次翻转,看是否满足题意,第一个满足题意的翻转次数即为最终结果。
实现代码如下:
#include <cstdio>
#include <iostream>
using namespace std;
int map[10][10]={0};//考虑到要不断翻转,我们用0和1代表棋盘黑白两种颜色,这样翻转就可以用“非”运算符来代替了
int dir[5][2]={{-1,0},{1,0},{0,-1},{0,1},{0,0}};
int sum;
bool flag;
void flip(int x,int y)//翻转(x,y)及其相邻点
{
for(int i=0;i<=4;i++)
map[x+dir[i][0]][y+dir[i][1]]=!map[x+dir[i][0]][y+dir[i][1]];
return ;
}
bool judge()//判断棋盘是否单色
{
int i,j;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
if(map[i][j]!=map[1][1])
return false;
return true;
}
void dfs(int x,int y,int ans)//ans纪录翻转次数
{
if(ans==sum)
{
flag=judge();
return ;
}
if(flag||x==5) return ;
flip(x,y);
if(y<4) dfs(x,y+1,ans+1);
else dfs(x+1,1,ans+1);
flip(x,y);
if(y<4) dfs(x,y+1,ans);
else dfs(x+1,1,ans);
return ;
}
int main()
{
int i,j;
char tmp;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
{
cin>>tmp;
if(tmp=='w') map[i][j]=1;//白色记为1,黑色记为0
}
for(sum=0;sum<=16;sum++)//枚举16次翻转
{
dfs(1,1,0);
if(flag) break;
}
if(flag) printf("%d\n",sum);
else puts("Impossible");
return 0;
}