题目链接:点击打开链接
题目意思:
4*4棋盘,用b代表黑棋,用w表示白棋,棋盘由b或w组成,问能否经过最小次数ans次翻转,使得棋盘上全为黑棋,或者全为白棋。(翻转的规则为翻转某一棋子,周围4个棋子翻转)
思路:
dfs。对于每一个棋子,我们有两种选择,即翻棋子,和不翻棋子,很自然先翻棋子,回溯时不翻棋子。
有一个问题,如何保证步数是最少的?
有一个思路,我们枚举答案,看是否这个答案能够逆推回到初始状态。
进而,我们想从小到大的枚举答案,倘若在答案所表示的步数下,实现全黑或者全白,那么当前解就是最小解。
题目启示参考我的专题小结:点击打开链接
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 4;
int step;
bool flag=false;
bool board[MAXN+2][MAXN+2];
const int dx[5] = {0, 0, 0, 1, -1};
const int dy[5] = {0, -1, 1, 0, 0};
bool check(){
for(int i=1; i<5; ++i)
for(int j=1; j<5; ++j)
if(board[i][j] != board[1][1])
return false;
return true;
}
void flip(int x, int y){
for(int i=0; i<5; ++i){
board[x+dx[i]][y+dy[i]] = !board[x+dx[i]][y+dy[i]];
}
}
void dfs(int x, int y, int cnt){
if(cnt==step){
flag = check();
return;
}
if(flag || x>=5) return; //给其他运行的函数返回
flip(x, y);
if(y<4)
dfs(x, y+1, cnt+1);
else
dfs(x+1, 1, cnt+1);
flip(x, y);
if(y<4)
dfs(x, y+1, cnt);
else
dfs(x+1, 1, cnt);
}
int main(){
char temp;
for(int i=1; i<5; ++i){
for(int j=1; j<5; ++j){
//scanf("%c", &temp);
cin>>temp;
if(temp=='b') board[i][j] = true;
else if(temp=='w') board[i][j] = false;
}
}
for(step=0; step<16; ++step){
dfs(1, 1, 0);
if(flag) break;
}
if(!flag)
printf("Impossible\n");
else
printf("%d\n", step);
return 0;
}