POJ2965

这道题有多种方法

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; 
} 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值