POJ1077(8数码问题)

该博客介绍了如何利用双向BFS策略解决8数码问题。作者通过自定义队列并记录路径作为模板,分别从起点和终点进行搜索。在搜索过程中,空格可以移动到四个方向,并根据题目要求排列状态。当双向搜索的队列相遇时,即可得出解决方案。需要注意在逆向搜索时,上下左右方向需转换。
摘要由CSDN通过智能技术生成

题目链接:http://poj.org/problem?id=1077

这个用BFS、双向BFS、Astar都能解决,这里先用双向BFS来做。

因为要输出路径,多以不能直接用STL中的queue容器,不然出队后就找不到了,所以就自己封装了一个队列,用数组模拟的,还增加了输出路径的功能,留下来当做模板来用大笑

这里让空格走四个方向,把状态按照题目给的方式排成一列,用康拓展开来记录状态,用两个队列同时从起点和终点出发,搜索四个方向,如果碰到在一个队列搜索到的新状态在另一个队列中出现过,这个时候就可以输出路径了。

要注意的是在逆向搜索的队列中所有的方向都是反的,注意 u 和 d 对换,l 和 r 对换。

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;

const int fac[9] = {1,1,2,6,24,120,720,5040,40320};
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};

struct node
{
    char state[12];
    int pos;
    int pre;
    char c;
};
node st, ed;
int a[10];
int b[10] = {9,1,2,3,4,5,6,7,8,0};
int f[400000];
int g[400000];

struct Queue  //自己封装的队列
{
    node q[400000];
    int Size;
    int head, tail;

    Queue()
    {
        Size = 0;
        head = tail = 0;
    }

    node front()
    {
        return q[head];
    }

    int indxHead()
    {
        return head;
    }

    int indextail()
    {
        return tail-1;
    }

    void pop()
    {
        head++;
    }

    void push(node a)
    {
        q[tail++] = a;
    }

    bool empty()
    {
        return head == tail;
    }

    void Find(int x, bool order)  //输出路径的函数,order表示是否是顺序的队列
    {
        if (order)  //顺序队列的路径输出
        {
            char path[1000] = {0};
            int cnt = 0;
            while (q[x].pre != -1)
            {
                path[cnt++] = q[x].c;
                x = q[x].pre;
            }
            for (int i=cnt-1; i>=0; i--)
                printf("%c",path[i]);
        }
        else  //逆序队列的输出
        {
            while (q[x].pre != -1)
            {
                printf("%c",q[x].c);
                x = q[x].pre;
            }
        }
    }
}Q,P; //Q是顺序队列,P事逆序队列

int contor(char *a, int n)  //康拓展开,序列映射成数字
{
    int sum = 0;
    for (int i=1; i<=n; i++)
    {
        int cnt = 0;
        for (int j=i+1; j<=n; j++)
            if (a[j] < a[i]) cnt++;
        sum += cnt*fac[n-i];
    }

    return sum;
}

bool next(node& now, int i,int pre, bool order = true) //计算状态now按照某个方向走之后的状态
{
    int nowi = (now.pos-1)/3+1;
    int nowj = now.pos-(nowi-1)*3;
    int newi = nowi+dx[i];
    int newj = nowj+dy[i];
    if (newi < 1 || newi > 3 || newj < 1 || newj > 3)
        return false;
    int newpos = (newi-1)*3+newj;
    char c = now.state[now.pos]; now.state[now.pos] = now.state[newpos]; now.state[newpos] = c;
    now.pos = newpos;
    now.pre = pre;
    switch (i)
    {
        case 0:now.c = order ? 'u' : 'd'; break;
        case 1:now.c = order ? 'r' : 'l'; break;
        case 2:now.c = order ? 'd' : 'u'; break;
        case 3:now.c = order ? 'l' : 'r'; break;
    }
    return true;
}

void BFS()  //双向BFS
{
    Q.push(st);
    P.push(ed);
    f[contor(st.state,9)] = 1;
    f[contor(ed.state,9)] = 2;
    while (!Q.empty() && !P.empty())
    {
        if (!Q.empty())
        {
            node now = Q.front();
            node tmp = now;
            Q.pop();
            for (int i=0; i<4; i++)
                if (next(now,i,Q.indxHead()-1))
            {
                node New = now;
                now = tmp;
                int newState = contor(New.state,9);
                if (f[newState] == 2)
                {
                    Q.push(New);
                    Q.Find(Q.indextail(),true);
                    P.Find(g[newState],false);
                    printf("\n");
                    return;
                }
                else if (f[newState] == 0)
                {
                    Q.push(New);
                    f[newState] = 1;
                    g[newState] = Q.indextail();
                }
            }
        }
        if (!P.empty())
        {
            node now = P.front();
            node tmp = now;
            P.pop();
            for (int i=0; i<4; i++)
                if (next(now,i,P.indxHead()-1,false))
            {
                node New = now;
                now = tmp;
                int newState = contor(New.state,9);
                if (f[newState] == 1)
                {
                    P.push(New);
                    Q.Find(g[newState],true);
                    P.Find(P.indextail(),false);
                    printf("\n");
                    return;
                }
                else if (f[newState] == 0)
                {
                    P.push(New);
                    f[newState] = 2;
                    g[newState] = P.indextail();
                }
            }
        }
    }
}

int main()
{

    string s;
    getline(cin,s);

    a[0] = 0;
    int cnt = 0;
    for (int i=0; i<s.size(); i++)
    {
        if (s[i] == ' ') continue;
        cnt++;
        if (s[i] >= '1' && s[i] <='8')
            st.state[cnt] = s[i];
        else if (s[i] == 'x')
        {
            st.state[cnt] = '0';
            st.pos = cnt;
        }
    }
    st.pre = -1;
    for (int i=1; i<=8; i++) ed.state[i] = '0' + i;
    ed.state[9] = '0';
    ed.pos = 9;
    ed.pre = -1;

    BFS();

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值