POJ 3131 Cubic Eight-Puzzle 双向BFS + HASH

超赞的一道搜索题,麻烦到没朋友,不过思路还是很清楚的。

双向搜索的时候需要注意一个地方就是起始状态只有一个,目标状态最多的时候感觉会有512个,所以要控制两个方向搜索的层数。第一次知道双向搜索还能控制层数,简直点赞。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 6000007

using namespace std;

char Map[5][5];

int Judge(char a,char b,char c)
{
    if(a == 'W')
    {
        if(b == 'R')
            return 0;
        return 5;
    }
    else if(a == 'R')
    {
        if(b == 'W')
            return 1;
        return 3;
    }
    else if(a == 'B')
    {
        if(b == 'R')
            return 2;
        return 4;
    }
    else return 6;
}

struct Q
{
    int sta,x,y,fl,ans;
};

int mark[3000010][2];

int jx[] = { 0, 0, 1,-1};
int jy[] = {-1, 1, 0, 0};

int re[10][10];

int bit[10];

struct H
{
    int site,data,next;
}st[Mod];

int head[Mod];

int Top_H;

int Query(int data,int Top)
{
    int temp = data%Mod;

    int p = head[temp];
    for(;p != -1; p = st[p].next)
    {
        if(st[p].data == data)
            return st[p].site;
    }

    p = Top_H++;
    st[p].data = data;
    st[p].site = Top;
    st[p].next = head[temp];
    head[temp] = p;
    return -1;
}

int bfs(int x,int y)
{
    Top_H = 0;
    memset(mark,-1,sizeof(mark));

    int Top = 0;

    int i,j;

    for(i = 0;i < Mod; ++i)
        head[i] = -1;

    int sta = 0;

    for(i = 0; i < 3; ++i)
    {
        for(j = 0; j < 3; ++j)
            if(i == x && j == y)
                sta += Judge('E','E','E')*bit[i*3+j+1];
            else
                sta += Judge('W','B','R')*bit[i*3+j+1];
    }

    Q f,t;
    queue<Q> q;

    f.sta = sta;
    f.ans = 0,f.x = x,f.y = y,f.fl = 0;
    q.push(f);

    Query(f.sta,Top);

    mark[Top][0] = 0;
    Top++;

    f.ans = 0;
    f.fl = 1;

    for(i = 0; i < 512; ++i)
    {
        sta = 0,x = 0,y = 0;
        for(j = 0; j < 9; ++j)
        {
            if(Map[x][y] == 'E')
            {
                f.x = x;
                f.y = y;
                sta += Judge('E','E','E')*bit[x*3+y+1];
            }
            else if(i&(1<<j))
            {
                if(Map[x][y] == 'W')
                    sta += Judge('W','R','B')*bit[x*3+y+1];
                else if(Map[x][y] == 'R')
                    sta += Judge('R','B','W')*bit[x*3+y+1];
                else
                    sta += Judge('B','R','W')*bit[x*3+y+1];
            }
            else
            {
                if(Map[x][y] == 'W')
                    sta += Judge('W','B','R')*bit[x*3+y+1];
                else if(Map[x][y] == 'R')
                    sta += Judge('R','W','B')*bit[x*3+y+1];
                else
                    sta += Judge('B','W','R')*bit[x*3+y+1];
            }
            y++;
            if(y == 3)
                y = 0,x++;
        }
        f.sta = sta;
        q.push(f);
        if(Query(f.sta,Top) == -1)
        {
            mark[Top++][1] = 0;
        }
        else
        {
            mark[Query(f.sta,Top)][1] = 0;
        }
    }

    int site,tsite,tdata;

    while(q.empty() == false)
    {
        f = q.front();
        q.pop();

        if((f.fl == 1 && f.ans > 9) || (f.fl == 0 && f.ans > 20))
            continue;

        if(mark[Query(f.sta,Top)][f.fl^1] != -1)
        {
            return mark[Query(f.sta,Top)][f.fl^1] + f.ans;
        }
        site = f.x*3 + f.y;

        t.fl = f.fl;
        t.ans = f.ans+1;

        for(i = 0; i < 4; ++i)
        {
            t.x = f.x + jx[i];
            t.y = f.y + jy[i];

            if(0 <= t.x && t.x <= 2 && 0 <= t.y && t.y <= 2)
            {
                tsite = t.x*3+t.y;
                tdata = f.sta/bit[tsite+1]%7;

                t.sta = f.sta/bit[tsite]*bit[tsite] + 6*bit[tsite+1] + f.sta%bit[tsite+1];
                t.sta = t.sta/bit[site]*bit[site] + re[tdata][i]*bit[site+1] + t.sta%bit[site+1];

                if(Query(t.sta,Top) == -1)
                {
                    mark[Top++][t.fl] = t.ans;
                    q.push(t);
                }
                else if(mark[Query(t.sta,Top)][t.fl] == -1)
                {
                    mark[Query(t.sta,Top)][t.fl] = t.ans;
                    q.push(t);
                }
            }
        }
    }
    return -1;
}

int main()
{
    re[0][0] = 1;
    re[0][1] = 1;
    re[0][2] = 2;
    re[0][3] = 2;

    re[1][0] = 0;
    re[1][1] = 0;
    re[1][2] = 4;
    re[1][3] = 4;

    re[2][0] = 3;
    re[2][1] = 3;
    re[2][2] = 0;
    re[2][3] = 0;

    re[3][0] = 2;
    re[3][1] = 2;
    re[3][2] = 5;
    re[3][3] = 5;

    re[4][0] = 5;
    re[4][1] = 5;
    re[4][2] = 1;
    re[4][3] = 1;

    re[5][0] = 4;
    re[5][1] = 4;
    re[5][2] = 3;
    re[5][3] = 3;

    int i,j,x,y;

    bit[9] = 1;

    for(i = 8; i >= 0; --i)
        bit[i] = bit[i+1]*7;

    while(scanf("%d %d",&y,&x) && (x||y))
    {

        for(i = 0; i < 3; ++i)
        {
            for(j = 0; j < 3; ++j)
            {
                scanf("%*c%c",&Map[i][j]);
            }
        }

        printf("%d\n",bfs(x-1,y-1));
    }

    return 0;
}

POJ 3131 Cubic Eight-Puzzle 双向BFS + HASH

时间: 2024-10-29 03:54:25

POJ 3131 Cubic Eight-Puzzle 双向BFS + HASH的相关文章

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

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

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拓展出其他可行状态并且顺带记录步数,直到所有的小鬼都到达终点.首先状态如何表示

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

Hdu1401-Solitaire(双向bfs)

Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.There are four identical pieces on the board. In one move it is allowed to

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