題目描述
翻轉游戲是這樣玩的:
有一張4*4的棋盤,在16個位置上每個位置放着一個棋子,棋子一面是黑色,另一面是白色,棋子或者白色面朝上,或者黑色面朝上。遊戲的走法如下:每一步先選擇一個位置,然後把該位置和上,下,左,右(不越界)相鄰位置上的棋子翻轉(白->黑,黑->白)。我們用w表示棋子白色面朝上,b表示黑色面朝上。
例如:考慮如下棋盤狀態:
bwbw
wwww
bbwb
bwwb
當我們選擇第三行,第一列的位置翻轉時,棋盤變化爲:
bwbw
bwww
wwwb
wwwb
遊戲的目的是用最少的步數把全部棋子變爲白色向上或黑色向上。
時限:1s。
輸入格式
4行由b和w組成的字符串描述的一個棋盤的初始狀態。
輸出格式
一個測試數據輸出一行,爲所需要的最少的翻轉次數,如果無法翻轉成目標狀態,則輸出’impossible’(小寫,沒有引號)。
樣例輸入(1)
bwbw
wwww
bbwb
bwwb
樣例輸出(1)
Impossible
樣例輸入(2)
bwwb
bbwb
bwwb
bwww
樣例輸出(2)
4
解題思路:
BFS搜索加哈希判重。將w設置爲0,b設置爲1。把16個位置的數據當做二進制數,將二進制轉換爲十進制數。
2^16=65536,用於判重的哈希數組並不會很大,可以實現。
類似的題目還有八數碼問題,只不過八數碼的哈希表爲康託展開。八數碼:https://www.rqnoj.cn/problem/70
AC代碼:
#include<iostream>
#include<queue>
#include<cstring>
usingnamespace std;
typedefstruct table
{
int pic[6][6];
}table;
tablestart; //初始狀態
intP[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
boolvis[65536]; //狀態數組
intdist[65536];
queue<table>Q;
//黑0 白1
charNegate(int ch)
{
if(ch)
return 0;
return 1;
}
voidturn(int x,int y,table &T)
{
T.pic[x][y]=Negate(T.pic[x][y]); //自身
T.pic[x][y-1]=Negate(T.pic[x][y-1]); //左側
T.pic[x][y+1]=Negate(T.pic[x][y+1]); //右側
T.pic[x-1][y]=Negate(T.pic[x-1][y]); //上側
T.pic[x+1][y]=Negate(T.pic[x+1][y]); //下側
}
intget_dec(table T) //位壓縮
{
int dec=0;
int s=0;
for(int i=4;i>0;--i)
for(int j=4;j>0;--j)
{
dec+=T.pic[i][j]*P[s];
s++;
}
return dec;
}
intBFS()
{
Q.push(start); //初始狀態入隊
int st=get_dec(start); //獲取索引
vis[st]=true;
int front=1,rear=2;
table Now;
while(front<rear)
{
Now=Q.front(); //頭結點出隊
Q.pop();
int index=get_dec(Now); //獲取索引
if(index==0||index==65535) //找到終點
return front;
for(int i=0;i<16;++i)
{
int x=i/4+1; //橫座標
int y=i%4+1; //縱座標
table Next=Now;
turn(x,y,Next); //變換求下一步
int ni=get_dec(Next);
if(!vis[ni])
{
vis[ni]=true;
Q.push(Next);
dist[rear]=dist[front]+1;
rear++;
}
}
front++;
}
return -1;
}
intmain()
{
for(int i=0;i<6;++i)
for(int j=0;j<6;++j)
start.pic[i][j]=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=4;++i)
for(int j=1;j<=4;++j)
{
char ch;
cin>>ch;
if(ch=='w')
start.pic[i][j]=0;
else
start.pic[i][j]=1;
}
int s=BFS();
if(s!=-1)
cout<<dist[s]<<endl;
else
cout<<"impossible"<<endl;
return 0;
}