题意简述
题目给出一个4X4棋盘(黑白两色),要求求出使棋盘成为一种颜色最少的翻转次数;如bwwb bbwb bwwb bwww需要四次翻转到白色.
算法分析
第一行开,要始翻转棋子的颜色,又不会造成此行混乱(即影响旁边的棋子),只能翻转其正下方的棋子。这样就出现个问题,就是正向的话第一行,永远不会翻转。反向的话最后一行永远不会翻转。(就会造成需要写两个方向的函数)同时不动第一行和最后一行,还有个问题 就是如果四个角翻转可以的话,是必须单独判断的,不然得不到正确答案。当然这个算法是就这个题的,其实很有问题。。。应该用一种可行通用算法来解决,后面会说
程序样例
#include <stdio.h>
unsigned short OneColor(char a[][4],unsigned short c)
{
unsigned short i,j,counter=0;
if(c == 1)//to white
{
if(a[0][0] ==0 && a[0][1] == 0 && a[1][0] == 0)
{
++counter;
a[0][0]=a[0][1]=a[1][0]=1;
}
if(a[0][2] ==0 && a[0][3] ==0 && a[1][3] == 0)
{
++counter;
a[0][2] = a[0][3] = a[1][3]=1;
}
if(a[3][0] == 0 && a[3][1] ==0 && a[2][0] == 0)
{
++counter;
a[3][0] = a[3][1] = a[2][0]=1;
}
if(a[3][3] == 0 && a[2][3] == 0 && a[3][2] == 0)
{
++counter;
a[3][3] = a[2][3] = a[3][2]=1;
}
for(i=0;i<3;++i)
{
for(j=0;j<4;++j)
{
if(a[i][j] != 1)
{
++counter;
++i;
a[i][j]^=1;
a[i-1][j]^=1;
if(j > 0)
a[i][j-1]^=1;
if(i < 3)
a[i+1][j]^=1;
if(j < 3)
a[i][j+1]^=1;
--i;
}
}
}
if(a[3][0] != 1 || a[3][1] != 1 || a[3][2] != 1 || a[3][3] != 1)
counter=20;
}else//to black
{
if(a[0][0] ==1 && a[0][1] ==1 && a[1][0] == 1)
{
++counter;
a[0][0]=a[0][1]=a[1][0]=0;
}
if(a[0][2] ==1 && a[0][3] ==1 && a[1][3] == 1)
{
++counter;
a[0][2] = a[0][3] = a[1][3]=0;
}
if(a[3][0] ==1 && a[3][1] ==1 && a[2][0] == 1)
{
++counter;
a[3][0] = a[3][1] = a[2][0]=0;
}
if(a[3][3] ==1 && a[2][3] ==1 && a[3][2] == 1)
{
++counter;
a[3][3] = a[2][3] = a[3][2]=0;
}
for(i=0;i<3;++i)
{
for(j=0;j<4;++j)
{
if(a[i][j] != 0)
{
++counter;
++i;
a[i][j]^=1;
a[i-1][j]^=0;
if(j > 0)
a[i][j-1]^=1;
if(i < 3)
a[i+1][j]^=1;
if(j < 3)
a[i][j+1]^=1;
--i;
}
}
}
if(a[3][0] != 0 || a[3][1] != 0 || a[3][2] != 0 || a[3][3] != 0)
counter=20;
}
return counter;
}
unsigned short OneColorn(char a[][4],unsigned short c)
{
unsigned short i,j,counter=0;
if(c == 1)//to white
{
if(a[0][0] ==0 && a[0][1] == 0 && a[1][0] == 0)
{
++counter;
a[0][0]=a[0][1]=a[1][0]=1;
}
if(a[0][2] ==0 && a[0][3] ==0 && a[1][3] == 0)
{
++counter;
a[0][2] = a[0][3] = a[1][3]=1;
}
if(a[3][0] == 0 && a[3][1] ==0 && a[2][0] == 0)
{
++counter;
a[3][0] = a[3][1] = a[2][0]=1;
}
if(a[3][3] == 0 && a[2][3] == 0 && a[3][2] == 0)
{
++counter;
a[3][3] = a[2][3] = a[3][2]=1;
}
for(i=3;i!=0;--i)
{
for(j=0;j<4;++j)
{
if(a[i][j] != 1)
{
++counter;
--i;
a[i][j]^=1;
if(i > 0)
a[i-1][j]^=1;
if(j > 0)
a[i][j-1]^=1;
a[i+1][j]^=1;
if(j < 3)
a[i][j+1]^=1;
++i;
}
}
}
if(a[0][0] != 1 || a[0][1] != 1 || a[0][2] != 1 || a[0][3] != 1)
counter=20;
}else//to black
{
if(a[0][0] ==1 && a[0][1] ==1 && a[1][0] == 1)
{
++counter;
a[0][0]=a[0][1]=a[1][0]=0;
}
if(a[0][2] ==1 && a[0][3] ==1 && a[1][3] == 1)
{
++counter;
a[0][2] = a[0][3] = a[1][3]=0;
}
if(a[3][0] ==1 && a[3][1] ==1 && a[2][0] == 1)
{
++counter;
a[3][0] = a[3][1] = a[2][0]=0;
}
if(a[3][3] ==1 && a[2][3] ==1 && a[3][2] == 1)
{
++counter;
a[3][3] = a[2][3] = a[3][2]=0;
}
for(i=3;i!=0;--i)
{
for(j=0;j<4;++j)
{
if(a[i][j] != 0)
{
++counter;
--i;
a[i][j]^=1;
if(i > 0)
a[i-1][j]^=1;
if(j > 0)
a[i][j-1]^=1;
a[i+1][j]^=1;
if(j < 3)
a[i][j+1]^=1;
++i;
}
}
}
if(a[0][0] != 0 || a[0][1] != 0 || a[0][2] != 0 || a[0][3] != 0)
counter=20;
}
return counter;
}
int main()
{
char a[4][4],b[4][4],c[4][4],d[4][4];//b==0 w==1
char ch;
unsigned short i,j;
for(j=0;j<4;++j)
{
for(i=0;i<4;++i)
{
scanf("%c",&ch);
if(ch == 'w')
{
a[j][i]=1;
b[j][i]=1;
c[j][i]=1;
d[j][i]=1;
}else
{
a[j][i]=0;
b[j][i]=0;
c[j][i]=0;
d[j][i]=0;
}
}
scanf("%c",&ch);
}
i=OneColor(a,1);
ch=OneColorn(b,1);
if(ch < i)
i=ch;
j=OneColor(c,0);
ch=OneColorn(d,0);
if(ch < j)
j=ch;
if(i < j)
j=i;
if(j == 20)
printf("Impossible\n");
else
printf("%u\n",j);
}
四个数组来存原始数据,分别从上到下(两次,一黑一白),从下到上(两次),最小的当作答案。
指标:
POJ评定 164K 0MS
思考:
无疑,这样的代码很冗杂,也很不好看,百度一下。用DFS+枚举(BFS也可以)来完成很方便,代码也很精炼~
参考:http://www.lvzejun.cn/?p=332