这道题有多种方法
1.暴力枚举
#include"stdio.h"
int i,j,num=0,min=17,turns[16]={0xf888,0xf444,0xf222,0xf111,0x8f88,0x4f44,0x2f22,0x1f11,0x88f8,0x44f4,
0x22f2,0x11f1,0x888f,0x444f,0x222f,0x111f};
int temchge[16]={0},change[16];
void turn(int nu,int depth,int steps)
{
if(nu==0xffff&&steps<min)
{
min=steps;
for(i=0;i<16;i++)change[i]=temchge[i];
return;
}
if(depth>=16)return;
temchge[depth]=1;
turn(nu^turns[depth],depth+1,steps+1);
temchge[depth]=0;
turn(nu,depth+1,steps);
}
main()
{
char c;
int steps=0;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
num=(num<<1)+((c=getchar())=='+'?0:1);
getchar();
}
turn(num,0,0);
printf("%d\n",min);
for(i=0;i<16;i++)
if(change[i])printf("%d %d\n",i/4+1,i%4+1);
return 0;
}
2.参照Discuss的简便方法,
参考高手的高效解法:
> 证明:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.
> 设置一个4*4的整型数组,初值为零,用于记录每个点的操作数,那么在每个'+'上的行和列的的位置都加1,得到结果模2(因为一个点进行偶数次操作的效果和没进行操作一样,这就是楼上说的取反的原理),然后计算整型数组中一的
> 个数即为操作数,一的位置为要操作的位置(其他原来操作数为偶数的因为操作并不发生效果,因此不进行操作)
*********************************
此上证其可以按以上步骤使数组中值都为‘-’
********************************
在上述证明中将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。
其实就是不模2的操作,作了许多的无用功。
以上的操作次序对结果无影响,如果存在一个最小的步骤,则此步骤一定在以上操作之中。(简单说下:因为以上操作已经包含了所有可改变欲改变位置的操作了)
而模2后的操作是去掉了所有无用功之后的操作,此操作同样包含最小步骤。
但模2后的操作去掉任何一个或几个步骤后,都不可能再得到全为‘-’的。(此同样可证明:因为操作次序无影响,先进行最小步骤,得到全为‘-’,如果还剩下m步,则在全为‘-’的数组状态下进行这m步操作后还得到一个全为
‘-’的数组状态,此只能是在同一个位置进行偶数次操作,与前文模2后矛盾,所以m=0),因此模2后的操作即为最小步骤的操作。
*/
代码如下
#include"stdio.h"
main()
{
int i,j,k,mark[4][4]={0},count=0;
char map[4][4];
for(i=0;i<4;i++)
scanf("%s",map[i]);
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(map[i][j]=='+')
{
for(k=0;k<4;k++)
{
mark[i][k]=!mark[i][k];
mark[k][j]=!mark[k][j];
}
mark[i][j]=!mark[i][j];
}
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(mark[i][j])count++;
printf("%d\n",count);
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(mark[i][j])printf("%d %d\n",i+1,j+1);
return 0;
}
3.BFS即宽搜
#include"stdio.h"
int turns[16]={0xf888,0xf444,0xf222,0xf111,0x8f88,0x4f44,0x2f22,0x1f11,0x88f8,0x44f4,0x22f2,
0x11f1,0x888f,0x444f,0x222f,0x111f};
int queue[65555],visited[65555],father[65555],path[65555],result[16];
int i,j,k,num=0,rear=0,flag=0,count=-1;
main()
{
char c;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
num=(num<<1)+((c=getchar())=='+'?0:1);
getchar();
}
if(num==0xffff)printf("0\n");
else
{
queue[0]=num;
father[0]=-1;
memset(visited,0,sizeof(visited));
visited[num]=1;
for(k=0;k<=rear;k++)
{
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
num=queue[k];
num^=turns[i*4+j];
if(!visited[num])
{
rear++;
queue[rear]=num;
father[rear]=k;
path[rear]=i*4+j;
visited[num]=1;
if(num==0xffff)flag=1;
}
if(flag)break;
}
if(flag)break;
}
if(flag)break;
}
while(rear>0)
{
count++;
result[count]=path[rear];
rear=father[rear];
}
printf("%d\n",count+1);
for(i=count;i>=0;i--) printf("%d %d\n",result[i]/4+1,result[i]%4+1);
}
return 0;
}