背景描述:
翻转游戏:在一个4x4的格子。每个格子里一个棋子,棋子有黑白两面。
规则:每次翻转一个棋子,该棋子翻转的同时,要翻转其相邻的所有棋子,即左侧、右侧、上侧、下侧。因此每次翻转可能翻转3-5次棋子。多次翻转直到所有棋子的颜色一样则完成。
问题:给你一个任意时刻的棋盘的棋子状态图,求到达全黑或全白的最短步数。例子如下:
Sample Input
1
bwwb
bbwb
bwwb
bwww
Sample Output
4
分析:
刚开始看的时候没有任何思路。看了网上的思路。
具体是一个矩阵,求该矩阵到达某一状态所需的最短步数。有两种方案
BFS:
即宽度枚举所有状态,把一步的所有状态考察个遍。比如从某个状态起,查看每个棋子翻转后的状态,如果有成功状态则返回,否则,对于每一个子状态继续枚举。
DFS:
即深度枚举所有状态,最多有16步,对于一步的,针对每个棋子深度搜索。两步也是。以此类推。
下面是 抄的别人的dfs的代码:
#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 m;
while(cin>>m)
{
for( int k = 0; k < m; k++ )
{
int i,j,step;
bool flag=false;
for( i = 0; i < 6;i++ )
{
for( j = 0; j < 6; j++)
{
chess[i][j]='*';
Chess[i][j]= 0;
}
}
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;
}