POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)

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 x and 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 R
0 0

Sample Output

0
3
13
23
29
30
-1
-1

Source

Japan 2006

思路:数据太大,先抽象出状态,再哈希一下,然后就是双向BFS。

#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;
#define INF 99999999

struct{
int step,state;
}t,que1[1000000],que2[1000000];

stack<int>stk;

bool vis1[5000007],vis2[5000007];
int top1,top2,bottom1,bottom2,mp[9],nxt[2][7]={{0,4,6,5,1,3,2},{0,5,3,2,6,1,4}},head[5000007],next[5000007],val[5000007],total;

int hashval(int x)
{
    int t,i;

    t=x%5000007;

    for(i=head[t];i!=-1;i=next[i])
    {
        if(val[i]==x) return i;
    }

    val[total]=x;
    next[total]=head[t];
    head[t]=total;
    total++;

    return total-1;
}

void pushtarget(int cnt,int state)
{
    if(cnt==-1)
    {
        vis2[hashval(state)]=1;
        que2[bottom2].step=0;
        que2[bottom2].state=state;
        bottom2++;

        return;
    }

    if(mp[cnt]%2)
    {
        pushtarget(cnt-1,state*7+mp[cnt]);
        pushtarget(cnt-1,state*7+mp[cnt]+1);
    }
    else pushtarget(cnt-1,state*7);
}

int getstate()
{
    int temp=0;

    for(int i=8;i>=0;i--)
    {
        temp=temp*7+mp[i];
    }

    return temp;
}

void spread(int x)
{
    int i=0,temp,cnt,old;

    while(i<9)
    {
        if(x%7==0) cnt=i;
        mp[i++]=x%7;
        x/=7;
    }

    cnt+=1;
    if(cnt>=0 && cnt<9 && cnt%3>0)
    {

        old=mp[cnt];
        mp[cnt-1]=nxt[0][mp[cnt]];
        mp[cnt]=0;

        stk.push(getstate());

        mp[cnt]=old;
        mp[cnt-1]=0;
    }
    cnt-=1;

    cnt-=1;
    if(cnt>=0 && cnt<9 && cnt%3<2)
    {
        old=mp[cnt];
        mp[cnt+1]=nxt[0][mp[cnt]];
        mp[cnt]=0;

        stk.push(getstate());

        mp[cnt]=old;
        mp[cnt+1]=0;
    }
    cnt+=1;

    cnt-=3;
    if(cnt>=0 && cnt<9)
    {
        old=mp[cnt];
        mp[cnt+3]=nxt[1][mp[cnt]];
        mp[cnt]=0;

        stk.push(getstate());

        mp[cnt]=old;
        mp[cnt+3]=0;
    }
    cnt+=3;

    cnt+=3;
    if(cnt>=0 && cnt<9)
    {
        old=mp[cnt];
        mp[cnt-3]=nxt[1][mp[cnt]];
        mp[cnt]=0;

        stk.push(getstate());

        mp[cnt]=old;
        mp[cnt-3]=0;
    }
    cnt-=3;
}

int bfs()
{
    int step1=0,step2=0,ans=INF,temp;

    for(step1=0;step1<=20;step1++)
    {

        while(top1<bottom1 && que1[top1].step==step1)
        {
            spread(que1[top1].state);

            while(!stk.empty())
            {
                temp=stk.top();
                stk.pop();

                if(vis2[hashval(temp)])
                {
                    return step1+step2+1;
                }

                if(!vis1[hashval(temp)])
                {
                    vis1[hashval(temp)]=1;
                    que1[bottom1].state=temp;
                    que1[bottom1].step=que1[top1].step+1;

                    bottom1++;
                }
            }

            top1++;
        }

        while(top2<bottom2 && que2[top2].step==step2 && step2<9)
        {
            spread(que2[top2].state);

            while(!stk.empty())
            {
                temp=stk.top();
                stk.pop();

                if(vis1[hashval(temp)]) return step1+step2+2;

                if(!vis2[hashval(temp)])
                {
                    vis2[hashval(temp)]=1;
                    que2[bottom2].state=temp;
                    que2[bottom2].step=step2+1;

                    bottom2++;
                }
            }

            top2++;
        }

        if(step2<9) step2++;
    }

    return -1;
}

int main()
{
    int x,y,i,j,temp;
    char ctemp;

    while(~scanf("%d%d",&y,&x) && x)
    {
        x--;
        y--;

        top1=top2=bottom1=bottom2=0;

        memset(vis1,0,sizeof vis1);
        memset(vis2,0,sizeof vis2);
        memset(head,-1,sizeof head);

        total=0;

        while(!stk.empty()) stk.pop();

        for(i=0;i<9;i++)
        {
            ctemp=getchar();

            if(ctemp=='\n' || ctemp==' ')
            {
                i--;
                continue;
            }

            if(ctemp=='W')mp[i]=1;
            else if(ctemp=='B') mp[i]=3;
            else if(ctemp=='R') mp[i]=5;
            else if(ctemp=='E') mp[i]=0;
        }

        pushtarget(8,0);

        temp=0;
        for(i=8;i>=0;i--)
        {
            if(i!=x*3+y) temp=temp*7+1;
            else temp*=7;
        }

        if(vis2[hashval(temp)])
        {
            printf("0\n");
            continue;
        }

        vis1[hashval(temp)]=1;

        que1[bottom1].step=0;
        que1[bottom1].state=temp;
        bottom1++;

        printf("%d\n",bfs());
    }
}

POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)

时间: 2024-10-01 04:37:26

POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)的相关文章

POJ 3131 Cubic Eight-Puzzle 双向BFS + HASH

超赞的一道搜索题,麻烦到没朋友,不过思路还是很清楚的. 双向搜索的时候需要注意一个地方就是起始状态只有一个,目标状态最多的时候感觉会有512个,所以要控制两个方向搜索的层数.第一次知道双向搜索还能控制层数,简直点赞. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue&

UVA-1604 Cubic Eight-Puzzle (双向BFS+状态压缩+限制搜索层数)

题目大意:立体的八数码问题,一次操作是滚动一次方块,问从初始状态到目标状态的最少滚动次数. 题目分析:这道题已知初始状态和目标状态,且又状态数目庞大,适宜用双向BFS.每个小方块有6种状态,整个大方格有9*6^8个状态.每个小方块用一位6进制数表示即可. 注意:状态转移时要谨慎,否则会出现意想不到的错误: 这道题的末状态有256(2^8)个,如果对搜索层数不加限制,即使双向BFS也会TLE的,当限制正向搜索15层逆向搜索15层至正向搜索27层反向搜索3层时都能AC(我下面贴出的程序是这样的),其

poj 1915 Knight Moves 【双向bfs】

Knight Moves Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22121   Accepted: 10332 Description Background Mr Somurolov, fabulous chess-gamer indeed, asserts that no one else but him can move knights from one position to another so fast

POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比较)

题目链接:Knight Moves 研究了一下双向BFS,不是很难,和普通的BFS一样,双向BFS不过是从 起点和终点同时开始搜索,可减少搜索时间 当两条搜索路线相遇时,结束. 貌似有一年百度的招聘 笔试,就是双向BFS.... 下面,比较一下BFS 和 双向BFS的用时: BFS STL的queue可能会浪费一点时间 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstrin

poj 1915 双向 BFS 利用数组 a[x][y] = a[cp.x][cp.y] + 1; b[x][y] = b[cp.x][cp.y] + 1;保留步数

#include<iostream>#include<queue> using namespace std; struct point{    int x, y;};point bufa[8] ={    {-2, 1}, {-1, 2}, {1, 2}, {2, 1},    {2, -1}, {1, -2}, {-1, -2}, {-2, -1}}; int n, a[305][305], b[305][305]; int rule(int x,int y)//判断是否符合棋盘

UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS &amp;&amp; 降维 &amp;&amp; 状压)

题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占用同一个位置,也不能在一步之内交换位置.输入保证所有空格连通,所有障碍格也连通,且任何一个2*2子网格中至少有一个障碍格.输出最少的步数.输入保证有解. 分析 :可以将当前所有小鬼的位置作为一个状态,然后模拟小鬼移动BFS拓展出其他可行状态并且顺带记录步数,直到所有的小鬼都到达终点.首先状态如何表示

BFS、双向BFS和A*

BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个终点.按骑士的走法(走日字),从起点到终点的最少移动多少次 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2RraXJjaGhvZmY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/g

Colour Hash (Uva 704 双向bfs)

Colour Hash Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description This puzzle consists of two wheels. Both wheels can rotate both clock and counter-clockwise. They contain 21 coloured pieces, 10 of which

UVa1601 - The Morning after Halloween(单向+双向BFS)

给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的是任意两个ghost不能在相同的位置,因此也不能出现任意两个ghost对穿,也就是原来是ab,移动之后是ba.每个迷宫图'#'表示墙,' '表示空地,小写字母表示ghost的起始位置,大写字母表示对应ghost的目标位置,比如'a'应该走到'A'.保证任意2×2的空间内都有一个'#'. 看起来就像是人数多了