POJ1753 Flip Game

題目鏈接:http://poj.org/problem?id=1753

題目大意:

        翻棋子游戲,給定一個4*4的棋盤上擺放的初始狀態,棋子有黑白兩色,求將所有棋子翻成同一色的最少步數。規則:每次最多翻轉一個棋子和其上下左右共五個棋子,則最少三個,因爲四個角上的棋子在邊界上,有兩個鄰居不存在。若無法翻轉成同一個顏色則輸出 "IImpossible",初始狀態即爲目標狀態時輸出0。

題目思路:

        棋子總共只有兩種顏色,則可用0或1表示當前狀態,共十六顆棋子則總共只有2^16=65536種狀態。

則我們可以用一個hash判重,將當前狀態一個十六位的二進制數轉換成十進制數標記。解決了狀態標記,判重問題,接下來就只需一個基礎的BFS即可!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 70000
int queue[MAX];
int step[MAX];  //記錄走到當前狀態的最少步數
int a[16];
int n,m;
void find(int x)  //將一個十進制數轉換成二進制數
{
     int i=16,k=0;
     while (i--)
     {
           a[k]=x%2;
           x=x/2;
           k++;
     }
}
int check()  //將二進制數轉換成十進制數
{
    int s=a[0],temp=1,i;
    for (i=1;i<16;i++)
    {
        temp*=2;
        s+=a[i]*temp;
    }
    return s;       
}
void bfs()
{
     int qe=0,qs=0,i,u; 
     queue[qe++]=n;  //初始狀態入隊
     step[n]=0; 
     while (qs<qe)
     {
           int temp=queue[qs++];
           if (temp==0||temp==65535)
           {
              m=step[temp];
              break;                           
           }
           find(temp);
           for (i=0;i<16;i++)  //每次最多有十六個狀態可擴展
           {
               int s,x,z,y;
               s=i-4;
               x=i+4;
               z=i-1;
               y=i+1;
               a[i]=(a[i]+1)%2;
               if (s>=0&&s<16)   //判斷與當前棋子相鄰的上方的棋子能否翻轉
                  a[s]=(a[s]+1)%2;
               if (x>=0&&x<16)
                  a[x]=(a[x]+1)%2;
               if ((y>=0&&y<16)&&i%4!=3)  //當前棋子在右邊界時,與其相鄰的右方的棋子不能翻轉
                  a[y]=(a[y]+1)%2;
               if ((z>=0&&z<16)&&i%4!=0)  //當前棋子在左邊界時,與其相鄰的左方的棋子不能翻轉
                  a[z]=(a[z]+1)%2;
               //printf("%d %d %d %d\n",a[s],a[x],a[z],a[y]);
               u=check();
               //printf("%d\n",u);
               if (step[u]==-1||(step[u]>step[temp]+1))  //判斷當前節點是否已擴展過,並且是否是最優。
               {
                  queue[qe++]=u;
                  step[u]=step[temp]+1;
               }
	      //將翻轉過的棋子復位,供下一次擴展
               a[i]=(a[i]+1)%2;
               if (s>=0&&s<16)
                  a[s]=(a[s]+1)%2;
               if (x>=0&&x<16)
                  a[x]=(a[x]+1)%2;
               if ((y>=0&&y<16)&&i%4!=3)
                  a[y]=(a[y]+1)%2;
               if (z>=0&&z<16&&i%4!=0)
                  a[z]=(a[z]+1)%2;
               //int t=check();
               //printf("\n");
               //printf("%d %d\n",u,step[u]);
           }
     }
}
int main()
{
    //while (1)
    //{
    int i,j,s=1;
    char c;
    n=0;  //記錄初始狀態的十進制數
    //memset(flag,0,sizeof(flag));
    memset(step,-1,sizeof(step));
    for (i=0;i<4;i++)
    {
        for (j=0;j<4;j++)
        {
            if (i!=0||j!=0)
               s*=2;
            c=getchar();
            if (c=='b')
            {
               n+=s*1;      
            }    
            else
            {
               n+=s*0; 
            }
            //printf("%d\n",n);
        }    
        getchar();
    }
    //printf("%d\n",n);
    m=-1;
    //system("pause");
    bfs();
    if (m!=-1)
       printf("%d\n",m);
    else
       printf("Impossible\n"); 
    //system("pause");
    //}
    return 0;    
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章