双向广搜 八数码

双向广搜还是一个很神奇的东西

//判重更神奇;

双广仅适用于有目标状态的题目;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
#include<cmath>
#include<map>
#include<set>
using namespace std;
const int maxx=362880 + 5;
const int mo=1e6+7;
struct rec{
    int tu[4][4];
    int x,y;
}q[maxx/2];
int b[4][4]={{0,0,0,0},{0,1,2,3},{0,8,0,4},{0,7,6,5}};
int zx[5]={0,1,0,0,-1},
    zy[5]={0,0,1,-1,0};
int vis[1000007],dis[1000007];
int h=0,t=1;
int incode(int x)
{
    long long ans=0;
    for(int i=3;i>=1;i--)
    {
        for(int j=3;j>=1;j--)
        {
            ans=ans*10+q[x].tu[i][j];
        }
    }       
    return ans%mo;
}

void bfs()
{
    vis[incode(1)]=1;
    vis[incode(2)]=2;
    t++;
    while(h<=t)
    {
        h++;
        int ct=incode(h);
        int nt;
        for(int i=1;i<=4;i++)
        {
            int nx=q[h].x,ny=q[h].y;
            int tx=nx+zx[i],ty=ny+zy[i];
            if(tx<4&&ty<4&&tx>0&&ty>0)
            {
                t++;
                q[t]=q[h];
                swap(q[t].tu[tx][ty],q[t].tu[nx][ny]);
                if(!vis[nt=incode(t)])
                {
                    vis[nt]=vis[ct];
                    dis[nt]=dis[ct]+1;
                    q[t].x=tx,q[t].y=ty;
                    //if(vis[nt]==1) show(t);
                }
                else if(vis[nt]!=vis[ct]) 
                {
                    cout<<dis[nt]+dis[ct]+1;
                    return;
                }
                else t--;
            }
        }
    }
}
int main()
{   
    //ios::sync_with_stdio(false);
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            char k; 
            cin>>k;
            int kk=k-'0';
            if(!kk)q[1].x=i,q[1].y=j,q[1].tu[i][j]=0;
            else q[1].tu[i][j]=kk;
            q[2].tu[i][j]=b[i][j];
            if(!b[i][j])q[2].x=i,q[2].y=j;
        }
    }
    bfs();
    return 0;
}

其实就是在原来的广搜队列里开始多push了一个终点状态,每次产生一个新状态的vis有两种一种是从正向拓展来的另一种是反向拓展来的,其他和正常搜一样,拓展节点的时候若vis=true判断是哪个方向来的,如果是从反方向来的那么结束搜索return dis[当前head节点]+dis[拓展到的节点]+1;

下面是普通广搜和双向广搜运行时间比较:
这里写图片描述

这里写图片描述

PS:判重真是个好东西,真得好好学;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值