开始刷poj,从初级开始,枚举题1753,题目简短的来说就是一个棋盘,4x4的,有黑白棋两种,
问输入一个棋盘,最少需要翻多少回棋子(每次翻一个,但其上下左右的棋子跟着会变化)
使得整个棋盘全部白色或者全部黑色。
菜鸟一个并没有什么好的想法,想了一会后开始看别的大神们的思路(特别感谢優YoU http://user.qzone.qq.com/289065406/blog/1299076400),选择了一种自己能理解的方法:就是暴力枚举,一共16个棋子,每个棋子翻奇数次就等同于翻1次,翻偶数次就等同于翻0次,所有情况如下:翻0次,翻一个棋子,翻2个棋子,翻3个棋子。。。翻16个棋子。翻0次就是直接去检查是否满足情况,翻一次一共有16种选择,所以有两个类似于计数器一样的变量,step和deep,step表示翻转次数,暴力枚举所以是0~16,而deep表示的是在某次数下对16个棋子的选择,比如step等于三,此时就是假设总共翻转三回,deep从0~3,选择第一个棋子翻,翻完后再选择,一共选择三步,结果不对返回,选择第一个棋子不翻。。
还有个重点是虽然是4x4的棋盘,但是用的是6x6的,只用中心位置,这样简化代码,对于边角上的棋子翻转不需要单独分类。
下面是用c写的代码:
#include <stdio.h>
#include <stdlib.h>
//输入棋盘4X4,黑白两种棋;翻一块棋其上下左右跟着翻动
int b[6][6]={0};
int r[5]={-1,1,0,0,0};
int c[5]={0,0,-1,1,0};
int flag;
int step;
int judge_all(void){
int i,j;
for(i=1;i<5;i++){
for(j=1;j<5;j++)
if(b[i][j]!=b[1][1])
return 0;
}
return 1;
}
void flip(int row,int col){
int i;
for(i=0;i<5;i++)
b[row+r[i]][col+c[i]]=!b[row+r[i]][col+c[i]];
return;
}
void dfs(int row,int col,int deep){
if(deep==step)
{
flag=judge_all();
return;
}
if(flag||row==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;
}
int main()
{
char s[6];
int i=1;
for(i;i<=4;i++){
int j=0;
scanf("%s",s);
for(j;j<4;j++)
{
if(s[j]=='b')
b[i][j+1]=1;
}
}
for(step=0;step<=16;step++){
dfs(1,1,0);
if(flag) break;
}
if(flag) printf("%d\n",step);
else
printf("Impossible\n");
return 0;
}
过了。