Eight POJ - 1077(经典双向BFS八数码)

题意

就是问你怎么走可以最后走成:1 2 3 4 5 6 8 x 的状态

思路

由于起点和终点已经知道所以可以用双向bfs,我们考虑bfs的树状图形

我们可以看到阴影部分的地方就是无用的地方,我们双向搜索的话,肯定能找到相同的一层!(注意这里是一层),所以我们双向bfs的策略就是:你走一层,我走一层,这样相会的时候就是路径最短的时候,因为层数相当于步数!至于路劲的问题就很简单了,用pre[i]记录i是由pre[i]走过来的,走的方式是path[i],注意从终点走过来的方向是相反的。还有当你输出的方案跟原答案不一样的时候没关系,因为我现在才知道这个问题的最优解不是唯一的,可以有多种走法,但是走的步数必须是最短的!!!例如我的输出就是ullddrurdllurrdlurd

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;

const int MAXN=400000;
struct node{
    int location,index;
    int str[10];
}num[MAXN];

int f[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int mx[4]={1,0,-1,0};
int my[4]={0,1,0,-1};
char dir[2][4]={{'d','r','u','l'},{'u','l','d','r'}};
int pre1[MAXN],pre2[MAXN];
int vis1[MAXN],vis2[MAXN];
int path1[MAXN],path2[MAXN];
node st,et;

int cantor(int *a)
{
    int t=8,sum=0;
    for(int i=0;i<9;i++)
    {
        int s=0;
        for(int j=i+1;j<9;j++) if(a[i]>a[j]) s++;
        sum+=s*f[t-i]; 
    }
    return sum+1;
}
 
queue <node> q1,q2;
int d2;
int fg=0;
void bfs()
{
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    vis1[st.index]=1;
    vis2[et.index]=2;
    q1.push(st);
    q2.push(et);
    pre1[st.index]=-1;
    pre2[et.index]=-1;
    while(!q1.empty()||!q2.empty())
    {
        int s1=q1.size();
        while(s1--)
        {
            node t=q1.front();q1.pop();
            if(vis2[t.index]==2){
                fg=1;
                d2=t.index;
                return;
            }
            for(int i=0;i<4;i++)
            {
                int xx=t.location/3+mx[i];int yy=t.location%3+my[i];
                if(xx>=0&&xx<3&&yy>=0&&yy<3)
                {
                    node t2;
                    for(int i=0;i<9;i++) t2.str[i]=t.str[i];
                    int tt=xx*3+yy;
                    swap(t2.str[tt],t2.str[t.location]);
                    t2.location=tt;
                    t2.index=cantor(t2.str);
                    if(!vis1[t2.index])
                    {
                        q1.push(t2);
                        vis1[t2.index]=1;
                        path1[t2.index]=i;
                        pre1[t2.index]=t.index;
                    } 
                }
            }
        }
        int s2=q2.size();
        while(s2--)
        {
            node t=q2.front();q2.pop();
            if(vis1[t.index]==1)
            {
                fg=1;
                d2=t.index;
                return;
            }
            for(int i=0;i<4;i++)
            {
                int xx=t.location/3+mx[i];int yy=t.location%3+my[i];
                if(xx>=0&&xx<3&&yy>=0&&yy<3)
                {
                    node t2;
                    for(int i=0;i<9;i++) t2.str[i]=t.str[i];
                    int tt=xx*3+yy;
                    swap(t2.str[tt],t2.str[t.location]);
                    t2.index=cantor(t2.str);
                    t2.location=tt;
                    if(!vis2[t2.index])
                    {
                        q2.push(t2);
                        vis2[t2.index]=2;
                        path2[t2.index]=i;
                        pre2[t2.index]=t.index;
                    } 
                }

            }
        }
    }
}

int dd1[MAXN],dd2[MAXN];
int main()
{    
    for(int i=0;i<9;i++)
    {
        et.str[i]=i+1;
        char t;cin>>t;
        if(t=='x') st.str[i]=9,st.location=i;
        else st.str[i]=t-'0';
    }
    et.location=8;
    et.index=cantor(et.str);
    st.index=cantor(st.str); 
    bfs();
    if(!fg) printf("unsolvable\n");
    else
    {
        int d1=d2;
        int cont=0;
        while(pre1[d1]!=-1)
        {
            dd1[cont++]=path1[d1];
            d1=pre1[d1];
        }
        for(int i=cont-1;i>=0;i--) printf("%c",dir[0][dd1[i]]);
        cont=0;
        d1=d2;
        while(pre2[d1]!=-1)
        {
            dd2[cont++]=path2[d1];
            d1=pre2[d1];
        }
        for(int i=0;i<cont;i++) printf("%c",dir[1][dd2[i]]);
    }
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值