题目连接:点击打开链接
解题思路:枚举所有状态,每个棋子有翻或不翻,因为要求最少翻动次数,所以每个棋子翻动奇数次等价于翻动1次,翻动偶数次等价于不翻,一共有2^16个状态,我用的是DFS,每次判断是否超出枚举范围,超出则枚举范围扩大一次,否则判断是否达到目标(定义一个函数扫描棋盘上是否有子不等于(1,1)位置的子,有则返回false,否则返回true)达到目标则搜索结束,否则搜索下一粒子的位置,直至达到本次枚举范围,网上大牛有用16进制表示棋盘状态来做的,代码也一并附上。
#include<iostream>
using namespace std;
char chess[6][6]={'*'};
bool Chess[6][6]={0};
bool finish()//判断是否全黑或全白
{
int i,j;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
if(Chess[i][j]!=Chess[1][1])
return false;
return true;
}
void flip(int m,int n)//翻棋操作
{
Chess[m][n]=!Chess[m][n];
Chess[m-1][n]=!Chess[m-1][n];
Chess[m+1][n]=!Chess[m+1][n];
Chess[m][n+1]=!Chess[m][n+1];
Chess[m][n-1]=!Chess[m][n-1];
}
bool dfs(int x,int y,int now,int deep)
{
if(now>deep) return false;//判断是否超出枚举范围
if(finish()) return true;
for(int i=x;i<=4;i++)
for(int j=y;j<=4;j++)
{
flip(i,j);//翻棋
if(j<4)//同一行的没翻完继续翻,翻完就翻下一行
{if(dfs(i,j+1,now+1,deep)) return true;}//同一行
else
{if(dfs(i+1,1,now+1,deep)) return true;}//下一行
flip(i,j);//不成功则翻回最后一粒子重新搜索下一个目标位
if(j==4)//如果一列翻完且搜索失败,下一轮翻棋重新由下一行第一列开始
y=1;
}
return false;
}
int main()
{
int i,j,step;
bool flag=false;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
{
cin>>chess[i][j];
if(chess[i][j]=='b')
Chess[i][j]=1;
}
for(step=0;step<=16;step++)//状态总共2^16种,即翻棋有翻0,1,2.....16粒子,共17种选择
if(dfs(1,1,0,step))
{
flag=true;
break;
}
if(flag)
cout<<step<<endl;
else
cout<<"Impossible\n";
return 0;
}