题目链接
思路:
其实自己并没有思路- Anyway,第一时间想到的肯定是dfs:
- 首先,翻一个棋子可以想成掐住这一格,翻一个板子。那么同一个板子翻两次是没有意义的。这点很容易想通。
- 明白了上面这条,就明白了每一局棋最多翻16次。
- 然后呢,就是写dfs(),而一般这种题的 dfs() 都不是那么好写的,这里略作点评。
dfs:
首先确定使用什么变量:当前在哪一格,要记录坐标row、col;求步数,要记录深度deep。
dfs()写作步骤:
- return条件:深度达到上限、已找到正解、图已经搜完。
- 动作(翻棋)。
- 动作后对下一深度 dfs
- 逆动作(翻回来)// 意思是在当前深度上不能往这一步走。
- 对当前深度的另一分支 dfs
- return ;
代码:
- 664K 266MS
//664K 266MS
#include <iostream>
using namespace std;
bool chess[6][6];//use 1..4
bool flag = false;
int step;
int nextto[4][2] = {1,0,-1,0,0,1,0,-1};
void input(){
char tp;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++){
cin>>tp;
if(tp == 'b')
chess[i][j] = true;
else
chess[i][j] = false;
}
return ;
}
bool judge(){
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;
}
bool check(int x,int y){
if(x<0 || x>4 || y<0 || y>4)
return false;
return true;
}
void flip(int row , int col){
chess[row][col] = !chess[row][col];
for(int i=0;i<4;i++){
int x = row + nextto[i][0];
int y = col + nextto[i][1];
if(check(x,y))
chess[x][y] = !chess[x][y];
}
return ;
}
void dfs(int row , int col , int deep){
//注意,deep是已经翻转的次数。
if(deep == step){
flag = judge();
return ;
}
if(flag)
return ;
if(row == 5 || col == 5)
return ;
//本格点是合法格点。
//并且,如果到这里没递归,说明:没到达最大深度、没搜到正解
flip(row,col);
if(col != 4)
dfs(row , col+1 , deep+1);
else
dfs(row+1 , 1 , deep+1);
flip(row,col);//翻回来
//如果此时没有找到正解,说明这条路不通,要换一个起点
if(col != 4)
dfs(row , col+1 , deep);
else
dfs(row+1 , 1 , deep);
return ;
}
void output(){
if(flag)
cout<<step<<endl;
else
cout<<"Impossible"<<endl;
return ;
}
int main(){
input();
//总想着想把代码写得尽可能整洁,就更容易出错,这在ACM比赛中并不是什么好事。
/* for(step = 0 ; !flag && step <= 16 ; step++)
dfs(1,1,0);
*/
for(step = 0 ; step <= 16 ; step++){
dfs(1,1,0);
if(flag)
break;
}
output();
return 0;
}