这道题的大致意思是:
给你一个4*4的方格,上面只有'b'和'w',他们分别代表棋子的正面和反面。现在你对棋盘的操作有翻转
其中的一个棋子,但是同时会使得这个棋子上边,下边,左边,右边的棋子也会翻转。这个操作可以有多次。
问经过N次操作后棋盘上的棋子全为正面或反面(也就是全为'b'或全为'w'),并使得N最小。
分析一下解题思路,首先能想到的是对整个棋盘进行搜索,但是这样在最糟糕的情况下,需要进行4^16
次,很可能会超时。所以我们需要考虑到更优的方法。
仔细读题就会发现翻转某个个棋子只能改变当前棋子,上下左右的棋子的状态。假设我们需要进行多次操
作使得棋盘全为'b',那么当我们翻转第j行的棋子,必须使的第j-1行的棋子全部变为'b',因为当我们翻转完第j行
的棋子后,就不能使得第j-1行的棋子发生改变(所以此时即使第j-1行的棋子有'w',也不能让它翻转了)。
经过以上分析,我们可以知道当第一行的棋子的翻转后,剩下的3行棋子如何翻转就确定,因为你翻转某
行的棋子,必须使得当前行的上一行的棋子达到目标状态。最后我们只需要检查最后一行的的棋子是否符合目
标状态就行了。
程序的大致步骤就是写一个dfs,来搜索第一行翻转的状态。然后根据第一行的状态来推出最后一行的状态
,判断是否达到目标状态,在这个过程中应该用一个值来记录在这种情况下的翻转次数。并不断更新这个值,
使得这个值最小。
代码如下:
#include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> using namespace std; const int error = 999999999; //用来表示达不到目标状态; int flip(int x, int y, int flag); //flag==1表示在全为'b'的时候翻转, //flag==2时,表示在全为'w'时翻转; int judge(int num, int flag); //flag==1表示在判断棋盘是否全为'b', //flag==2表示是否全为'a'; int dfs(int index, int sum); //深搜第一行的所有翻转状态, //sum表示第一行翻转的次数。 char data[6][6], data1[6][6], data2[6][6]; //data1表示在全为'b'的棋盘,data1表示在全为'w'的棋盘 int vis[5] = {0}; //用来在深搜时表示第一行的翻转状态,1代表翻转,0代表不翻转。 int dir[5][2] = {0,0,-1,0,0,-1,1,0,0,1}; //表示翻转的方向 int result = error; /* Sample Input bwwb bbwb bwwb bwww bbbb bbbb bbbb bbbb bbbb bbbb bbbb wwww Sample Output 4 */ int main() { for(int i = 1; i <= 4; i++) { for(int j =1; j <= 4; j++) cin>>data[i][j]; } dfs(0,0); if(result == error) printf("Impossible\n"); else printf("%d\n",result); return 0; } int flip(int x, int y, int flag) { if(flag == 1) { for(int i = 0;i < 5; i++) { int next_x = x + dir[i][0]; int next_y = y + dir[i][1]; if(data1[next_x][next_y] == 'b') data1[next_x][next_y] = 'w'; else data1[next_x][next_y] = 'b'; } } else { for(int i = 0; i < 5; i++) { int next_x = x + dir[i][0]; int next_y = y + dir[i][1]; if(data2[next_x][next_y] == 'b') data2[next_x][next_y] = 'w'; else data2[next_x][next_y] = 'b'; } } } int judge(int num, int flag) { int step = num; if(flag == 1) { for(int i = 2; i <= 4; i++) { for(int j = 1; j <= 4; j++) { if(data1[i-1][j] != 'b') { flip(i, j, flag); step++; } } } for(int i = 1; i <= 4; i++) //根据最后一行状态判断是否达到目标状态 if(data1[4][i] != 'b') return error; return step; } else if(flag == 2) { for(int i = 2; i <= 4; i++) { for(int j = 1; j <= 4; j++) { if(data2[i-1][j] != 'w') { flip(i, j, flag); step++; } } } for(int i = 1; i <= 4; i++) //根据最后一行状态判断是否达到目标状态 if(data2[4][i] != 'w') return error; return step; } } int dfs(int index, int sum) { if(index == 4) { memcpy(data1, data, sizeof(data1)); for(int i = 1; i <= 4; i++) { if(vis[i] == 1) { flip(1,i,1); } } memcpy(data2, data1, sizeof(data1)); int b =judge(sum, 1); int w = judge(sum, 2); result = min(result , min(b , w)); return 0; } else { vis[index+1] = 0; dfs(index+1, sum); vis[index+1] = 1; dfs(index+1, sum+1); } }