zoukankan      html  css  js  c++  java
  • poj1753 flip game题解

     

     题目描述:

    Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:
    1. Choose any one of the 16 pieces.
    2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

    Consider the following position as an example:

    bwbw
    wwww
    bbwb
    bwwb
    Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:

    bwbw
    bwww
    wwwb
    wwwb
    The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.

    Input

    The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

    Output

    Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes).
    题目分析

    棋盘上共有16颗棋子,每个棋子只有黑白两种状态,故我可以将其看成一个16为的二进制数,黑为1白为0,每次翻棋子生成的棋盘相当于跟对应的数做一次异或运算,最后用一个广搜将搞定。   下面是我的代码

    #include<iostream>
    #include<cmath>
    using namespace std;
    int main()
    {
     int os=0;//orignal state
     int fs[131072];// fliped state:队列
        // flip number
        const int fn[16]={ 51200,58368,29184,12544,35968,20032,10016,4880,
                     2248, 1252, 626, 305, 140, 78, 39, 19}; 
        //棋板存在状态登记数组
     int exist[65536];
     memset(exist,0,sizeof(exist));
    
    
     //接收输入并将其转化成整数
     for(int i=0;i<16;i++)
     {
      char temp;
      cin>>temp;
      int base=(temp=='b' ? 1:0);//黑为1,白为0
            os+=(int)base*pow((double)2,15-i);
     }
        
     fs[0]=os;
     int out=0;
     int in=1;
     int levelEnd=0;
     int levelCount=0;
     bool flag=true;
     while(flag && out<=levelEnd)
     {
      while(out<=levelEnd)
      {
       int chudui=fs[out]; 
       if( chudui==65535 || chudui==0 )
       {
        flag=false;
        break;
       }
       for(int i=0;i<16;i++)
       {
        int fliped=chudui^fn[i];
        //如果不曾出现过
        if(exist[fliped]==0) 
        {
         fs[in]=fliped;
         exist[fliped]++;
         in++;
        }
       }
       out++;
      }
      levelCount++;
      levelEnd=in-1;
     }
     if(out>levelEnd)
      cout<<"Impossible"<<endl;
     else cout<<levelCount-1<<endl;
     return 0;
    }

    其中需要注意的就是我的存取位置标志in,in表示我下次入队的位置,因为对头在while循环外已经入队

    了,所以in应该从1开始,故每扫完一层,应将in-1赋给下一层的层尾levelEnd(开始我直接将in赋给

    levelEnd,卡了我两天啊)

       另外该方法的时间开销是32毫秒,相比在网上看到的一个很不好理解的方法效率要低一些下面是他的

    代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 using namespace std;
     6 char map[5][5];
     7 bool flip[7][7];
     8 int m=20;
     9 void change(int a,int b,int c,int d,char color)
    10 {
    11     int i,j,count=a+b+c+d;
    12     flip[1][1]=a;
    13  flip[1][2]=b;
    14  flip[1][3]=c;
    15  flip[1][4]=d;
    16     for(i=1;i<4;i++)
    17     {
    18         for(j=0;j<4;j++)
    19         {
    20             if(map[i-1][j]==color)
    21                 flip[i+1][j+1]=(flip[i][j+1]+flip[i][j]+flip[i][j+2]+flip[i-1][j+1])%2;
    22             else
    23                 flip[i+1][j+1]=(flip[i][j+1]+flip[i][j]+flip[i][j+2]+flip[i-1][j+1]+1)%2;
    24             count+=flip[i+1][j+1];
    25         }
    26     }
    27     for(j=0;j<4;j++)
    28     {
    29         int f=(map[3][j]==color) ? 1 : -1;
    30         if(f==1 && (flip[4][j+1]+flip[3][j+1]+flip[4][j]+flip[4][j+2])%2!=0)
    31             break;
    32         if(f==-1 && (flip[4][j+1]+flip[3][j+1]+flip[4][j]+flip[4][j+2])%2==0)
    33             break;
    34     }
    35     if(j==4 && count<m)
    36         m=count;
    37 }
    38 int main ()
    39 {
    40     int a,b,c,d;
    41     for(int i=0;i<4;i++)
    42         scanf("%s",map[i]);
    43     for(i=1;i<=4;i++)
    44     {
    45         flip[0][i]=0;flip[i][0]=0;flip[i][5]=0;//flip[ ]数组边界置为0
    46     }
    47     for(a=0;a<2;a++)
    48       for(b=0;b<2;b++)
    49             for(c=0;c<2;c++)
    50                 for(d=0;d<2;d++)
    51                 {
    52                     change(a,b,c,d,'w');
    53                     change(a,b,c,d,'b');
    54                 }
    55     if(m==20)
    56         printf("Impossible\n");
    57     else
    58         printf("%d\n",m);
    59     return 0;
    60 }

    目前本人尚无法理解这个神奇的方法,等待大牛指点

    Bingo,go,go,go!
  • 相关阅读:
    如何制作对联式广告所需的flash图像文件
    GHOST重装系统详解
    Multipledimensional Vector,C++
    Dvbbs展区图片调用(向上滚动样式)
    fatal error C1001: INTERNAL COMPILER ERROR
    硬盘坏道的探测与恢复
    FreeBSD 使用手册
    全美电影票房排行(截止2010.12.19)
    Linux环境下的C/C+基础调试技术2——程序控制
    在freebsd下安装vim(Debian下类似)
  • 原文地址:https://www.cnblogs.com/chenhaibin/p/1990574.html
Copyright © 2011-2022 走看看