poj 3131 Cubic Eight-Puzzle (雙向bfs+深度控制 立體八數位)

來源:互聯網
上載者:User
Cubic Eight-Puzzle
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 1344   Accepted: 451

Description

Let’s play a puzzle using eight cubes placed on a 3 × 3 board leaving one empty square.

Faces of cubes are painted with three colors. As a puzzle step, you can roll one of the cubes to a adjacent empty square. Your goal is to make the specified color pattern visible from above by a number of such steps.

The rules of this puzzle are as follows.

  1. Coloring of Cubes: All the cubes area colored in the same way as shown in Figure 1. The opposite faces have the same color.

    Figure 1: Coloring of a cube

  2. Initial Board State: Eight cubes are placed on the 3 × 3 board leaving one empty square. All the cubes have the same orientation as shown in Figure 2. As shown in the figure, squares on the board are given xand y coordinates,
    (1, 1), (1, 2), …, and (3, 3). The position of the initially empty square may vary.

    Figure 2: Initial board state

  3. Rolling Cubes: At each step, we can choose one of the cubes adjacent to the empty square and roll it into the empty square, leaving the original position empty. Figure 3 shows an example.

    Figure 3: Rolling a cube

  4. Goal: The goal of this puzzle is to arrange the cubes so that their top faces form the specified color pattern by a number of cube rolling steps described above.

Your task is to write a program that finds the minimum number of steps required to make the specified color pattern from the given initial state.

Input

The input is a sequence of datasets. The end of the input is indicated by a line containing two zeros separated by a space. The number of datasets is less than 16. Each dataset is formatted as follows.

x y  
F11 F21 F31
F12 F22 F32
F13 F23 F33

The first line contains two integers x and y separated by a space, indicating the position (xy) of the initially empty square. The values of x and y are 1, 2, or 3.

The following three lines specify the color pattern to make. Each line contains three characters F1jF2j, and F3j, separated by a space. Character Fij indicates
the top color of the cube, if any, at the position (ij) as follows:

B: Blue,

W: White,

R: Red,

E: the square is Empty.

There is exactly one ‘E’ character in each dataset.

Output

For each dataset, output the minimum number of steps to achieve the goal, when the goal can be reached within 30 steps. Otherwise, output “-1” for the dataset.

Sample Input

1 2 W W W E W W W W W 2 1 R B W R W W E W W 3 3 W B W B R E R B R 3 3 B W R B W R B E R 2 1 B B B B R B B R E 1 1 R R R W W W R R E 2 1 R R R B W B R R E 3 2 R R R W E W R R R0 0

Sample Output

0 3 13 23 29 
30 -1 -1

題意:這是一個立體的8數位問題,不過有點區別,有8個立體的正方體擺在3*3的地區內,留一個空格方便移動。移動的規則是:空格旁邊的小正方體可以滾動到空格位置,小正方體原來的位置變成空格。每個小正方體6個面有3中顏色,對面顏色相同,分別是white,blue,red。初始狀態每個小正方體的擺放方式都一樣,從正面看上面是white,前面是red,右面是blue,空格位置給定。現在給定一個初始的空格位置以及一個終態的上表面的顏色分布,求是否能在30步內從初態到終態,能,輸出最少步數,不能,輸出-1,注意給定的終態只是上表面的顏色分布,其他面上的顏色不做要求。

思路:bfs。這題狀態數非常之多,時間空間都要求很高,如果單向bfs,時空複雜度都太高,因此選擇雙向bfs。首先要解決的是判重問題,這題不像二維平面的8數位,每個位置只有一個狀態,因此可以用康托判重,這題每個位置的小方塊有6個狀態,加上空格,每個位置有7個狀態,那麼總的狀態數就是7^9,顯然還是太大了。再考慮到9個位置只能有一個位置是空格,可以把空格單獨拿出來判重,這樣空間複雜度就降到了6^8*9,勉強可以接受。
這就需要用六進位數表示狀態,然後判重也好判了,最後的問題就是類比方塊的滾動了,4個方向滾動,狀態會發生怎樣的變化都要在草稿紙上畫清楚。
ps:這題還要說明一點  因為初狀態只有一種  末狀態卻有2^8種  所以從前往後搜和從後往前搜搜的深度得不一樣才行  從前往後多搜點  才能保證雙搜沿棱形展開   我是這樣控制的  從前往後:21層  從後往前:9層。

感想:這題程式碼還是蠻長的   所以要思路清晰  想好了 準備好了再下手  不然debug會很不好搞的  

代碼:(我的程式用的STL    也可以改為自己的隊列的  會快一點點  方便看 我就只貼STL代碼好了 )
//  Memory    31352 KB    Time   2250 ms  
#include <iostream>#include <cstdio>#include <cstring>#include <queue>#define maxn 1679616    // 6^8using namespace std;int n,m,x,y,ans,dfspos;int six[]= {1,6,36,216,1296,7776,46656,279936};int state[3][3];            //  根據前上推狀態int roll[6][4]=             // 狀態滾動後的狀態{    2,2,5,5,    4,4,3,3,    0,0,4,4,    5,5,1,1,    1,1,2,2,    3,3,0,0};bool vis1[9][maxn];bool vis2[9][maxn];int mp[9];int dx[]= {-1,1,0,0};int dy[]= {0,0,-1,1};int undir[]= {1,0,3,2};int dight[8];struct Node{    int pos;    int sta;    int step;} cur,now;queue<Node>q1,q2;int getdight(int xx,int k)         // 開始是按十進位提取的  想錯了  應該是提取六進位{    int i,j,t;    if(k==0) t=xx%6;    else    {        t=1;        for(i=1; i<=k; i++)            t*=6;        t=(xx/t)%6;    }    return t;}bool bfs(int k){    int i,j,mi,cnt1,cnt2,npos,nsta,nx,ny,temp,nstep,flag;    int tx,ty,tpos,tsta,tstadt;    memset(vis1,0,sizeof(vis1));    while(!q1.empty()) q1.pop();    cur.pos=k;    cur.sta=0;    vis1[k][0]=1;    cur.step=0;    q1.push(cur);    cnt1=0;    cnt2=0;    while(1)    {        flag=0;        while(q1.front().step<=cnt1&&!q1.empty())        {            flag=1;            now=q1.front();            q1.pop();            npos=now.pos;            nsta=now.sta;            nstep=now.step;            nx=npos/3;            ny=npos%3;            if(vis2[npos][nsta])            {                ans=nstep+cnt2;                return true ;            }//            printf("pos:%d step:%d sta:%d nx:%d ny:%d\n",npos,nstep,nsta,nx,ny);            for(i=0; i<8; i++)            {                dight[i]=getdight(nsta,i);            }            for(i=0; i<4; i++)            {                tx=nx+dx[i];                ty=ny+dy[i];                if(tx>=0&&tx<3&&ty>=0&&ty<3&&nstep<21)                {//                    printf("tx:%d ty:%d\n",tx,ty);                    tpos=tx*3+ty;                    if(i==2||i==3)           // 左右滾動不會改變相對位置大小 可直接處理                    {                        mi=npos>tpos?tpos:npos;                        tstadt=roll[dight[mi]][undir[i]];                        tsta=nsta-six[mi]*dight[mi]+six[mi]*tstadt;                        if(!vis1[tpos][tsta])                        {                            vis1[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q1.push(cur);                        }                    }                    else if(i==0)            // 向下滾動  要影響三個數的值                    {                        tstadt=roll[dight[tpos]][undir[i]];                        tsta=nsta;                        for(j=tpos; j<npos; j++)                        {                            tsta-=six[j]*dight[j];                        }                        tsta+=tstadt*six[npos-1];                        for(j=tpos+1; j<npos; j++)                        {                            tsta+=six[j-1]*dight[j];                        }                        if(!vis1[tpos][tsta])                        {                            vis1[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q1.push(cur);                        }                    }                    else if(i==1)            // 向上滾動  也要影響三個數的值                    {                        tstadt=roll[dight[tpos-1]][undir[i]];                        tsta=nsta;                        for(j=npos; j<tpos; j++)                        {                            tsta-=six[j]*dight[j];                        }                        tsta+=tstadt*six[npos];                        for(j=npos; j<tpos-1; j++)                        {                            tsta+=six[j+1]*dight[j];          // 開始就錯在這裡了  j忘記+1了                        }                        if(!vis1[tpos][tsta])                        {                            vis1[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q1.push(cur);                        }                    }                }            }        }        if(cnt1<21) cnt1++;                  // 設定深度 從前往後不超過21層        while(q2.front().step<=cnt2&&!q2.empty())        {            flag=1;            now=q2.front();            q2.pop();            npos=now.pos;            nsta=now.sta;            nstep=now.step;            nx=npos/3;            ny=npos%3;            if(vis1[npos][nsta])            {                ans=cnt1+nstep;                return true ;            }//            printf("pos:%d step:%d sta:%d nx:%d ny:%d\n",npos,nstep,nsta,nx,ny);            for(i=0; i<8; i++)            {                dight[i]=getdight(nsta,i);            }            for(i=0; i<4; i++)            {                tx=nx+dx[i];                ty=ny+dy[i];                if(tx>=0&&tx<3&&ty>=0&&ty<3&&nstep<9)                {//                    printf("tx:%d ty:%d\n",tx,ty);                    tpos=tx*3+ty;                    if(i==2||i==3)           // 左右滾動不會改變相對位置大小 可直接處理                    {                        mi=npos>tpos?tpos:npos;                        tstadt=roll[dight[mi]][undir[i]];                        tsta=nsta-six[mi]*dight[mi]+six[mi]*tstadt;                        if(!vis2[tpos][tsta])                        {                            vis2[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q2.push(cur);                        }                    }                    else if(i==0)            // 向下滾動  要影響三個數的值                    {                        tstadt=roll[dight[tpos]][undir[i]];                        tsta=nsta;                        for(j=tpos; j<npos; j++)                        {                            tsta-=six[j]*dight[j];                        }                        tsta+=tstadt*six[npos-1];                        for(j=tpos+1; j<npos; j++)                        {                            tsta+=six[j-1]*dight[j];                        }                        if(!vis2[tpos][tsta])                        {                            vis2[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q2.push(cur);                        }                    }                    else if(i==1)            // 向上滾動  也要影響三個數的值                    {                        tstadt=roll[dight[tpos-1]][undir[i]];                        tsta=nsta;                        for(j=npos; j<tpos; j++)                        {                            tsta-=six[j]*dight[j];                        }                        tsta+=tstadt*six[npos];                        for(j=npos; j<tpos-1; j++)                        {                            tsta+=six[j+1]*dight[j];                        }                        if(!vis2[tpos][tsta])                        {                            vis2[tpos][tsta]=1;                            cur.step=nstep+1;                            cur.pos=tpos;                            cur.sta=tsta;                            q2.push(cur);                        }                    }                }            }        }        if(cnt2<9) cnt2++;                 // 從後往前不超過9步        if(!flag) return false ;    }}void dfs(int kk,int ssta,int tt)           // 訪問到第幾個數  狀態  已經加進來了幾個數{    int i,j,temp;    if(kk>8)    {        if(!vis2[dfspos][ssta])                  // 這裡的dfspos得用全域變數        {            vis2[dfspos][ssta]=1;            cur.step=0;            cur.sta=ssta;//            printf("pos:%d ssta:%d\n",dfspos,ssta);            q2.push(cur);        }        return ;    }    if(mp[kk]==-1)    {        dfspos=kk;        dfs(kk+1,ssta,tt);    }    else    {        temp=mp[kk]*six[tt];        dfs(kk+1,ssta+temp,tt+1);        temp=(mp[kk]+1)*six[tt];        dfs(kk+1,ssta+temp,tt+1);    }}int main(){    int i,j,t,tst,tpos,temp;    char s[3];    state[0][1]=0;    state[0][2]=1;    state[1][0]=2;    state[1][2]=3;    state[2][0]=4;    state[2][1]=5;    while(scanf("%d%d",&x,&y),x||y)    {        x--;        y--;        t=y*3+x;        for(i=0; i<3; i++)        {            for(j=0; j<3; j++)            {                scanf("%s",s);                temp=i*3+j;                if(s[0]=='W') mp[temp]=0;                else if(s[0]=='R') mp[temp]=2;                else if(s[0]=='B') mp[temp]=4;                else                {                    mp[temp]=-1;                    tpos=i*3+j;                }            }        }        cur.pos=tpos;        memset(vis2,0,sizeof(vis2));        while(!q2.empty()) q2.pop();        dfs(0,0,0);                    // 將終態進隊列        if(bfs(t)) printf("%d\n",ans);        else printf("-1\n");    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.