小白书隐式图搜索之八数码问题

这题也是一个隐式图的问题,bfs即可,既是简单bfs的结构体办,

用一个二维数组去存储每次可到达的点的状态,这题既是一个二维数组去存储九个数的状态,

另外记得要写初始化函数look_up_table()和判重函数insert(),(即简单那bfs中的vis数组),俩个条件均满足方可

插入队列,由于要存储状态这里用数组去代替队列更容易,而且可以增加二维数组的第二维的维数用来存储距离或者父节点

坐标。

代码中给出三种判重的方式,分别是容器set判重,编码判重,(这里的编码函数其实就是一个完美的哈希函数),哈希判重。

三种方式的比较:

1.编码解码法的使用范围并不大,如果隐式图的总结点数非常大,编码也将会很大,数组还是开不下。

2.哈希表的执行效率高,适用范围也很广。还可以把它用到其他需要快速查找的地方。不过要注意的是:

在哈希表中,对效率起到关键作用的是哈希函数。如果哈希函数选取得当,几乎不会有结点的哈希值相同,且此时链表查找的速度也比较快。

但如果冲突严重,整个哈希表会退化成少数几条长长的链表,查找速度将非常慢。

3.STL要求set的元素类型必须定义小于运算符。一些函数库中自带的不需要重载小于运算符,其他均需要,重载方法在下面代码中。

另外注意调用memcpy比直接比较俩个整数要慢的多。三种实现中,使用STL集合的代码最简单,但时间效率也最低。一般在时间

紧迫或对效率要求不太高的情况下使用,或者自己先写一个STL,然后又替换成哈希表。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<climits>
using namespace std;
const int N=1e6+10;
int st[N][10];
int cup[9];
const int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
/*struct cmp
{
    bool operator()(int a,int b) const
    {
        return memcmp(&st[a],&st[b],sizeof(cup))<0;
    }
};*/
set<int> vis;
void look_up_table()
{
    vis.clear();
}
int insert(int s)
{
    int v=0;
    for(int i=0;i<9;i++)
        v=v*10+st[s][i];
    if(vis.count(v)) return 0;
    vis.insert(v);
    return 1;
}
/*int vvis[N],fact[9];
void look_up_table()
{
   // memset(vvis,0,sizeof(vvis));
    fact[0]=1;
    for(int i=1;i<9;i++) fact[i]=fact[i-1]*i;
}
int insert(int s)
{
    int code=0;

    for(int i=0;i<9;i++)
    {
        int cnt=0;
        for(int j=i+1;j<9;j++) if(st[s][j]<st[s][i]) cnt++;
        code+= fact[8-i]*cnt;
    }
    if(vvis[code]) return 0;

    vvis[code]=1;

    return 1;

}*/
/*const int MAXN=1000003;
int head[MAXN],next[MAXN];
void look_up_table()
{
    memset(head,0,sizeof(head));
}
int hash(int s)
{
    int v=0;
    for(int i=0;i<9;i++)
        v=v*10+st[s][i];
    return v%MAXN;
}
int insert(int s)
{
    int h=hash(s);
    int u=head[h];
    while(u)
    {
        if(memcmp(st[u],st[s],sizeof(cup))==0) return 0;
        u=next[u];
    }
    next[s]=head[h];
    head[h]=s;
    return 1;
}*/
int bfs()
{
    look_up_table();
   int front=1,rear=2;
   while(front<rear)
   {
       int buf[9];
       memcpy(buf,st[front],sizeof(buf));
       if(memcmp(cup,buf,sizeof(buf))==0)
        return front;
       int z;
       for(z=0;z<9;z++) if(!buf[z]) break;
       int x=z/3,y=z%3;
       for(int i=0;i<4;i++)
       {
           int newx=x+dx[i],newy=y+dy[i];
           int newz=newx*3+newy;
           if(newx>=0&&newx<3&&newy>=0&&newy<3)
           {
               memcpy(st[rear],buf,sizeof(buf));
               st[rear][z]=st[front][newz];
               st[rear][newz]=st[front][z];
               if(insert(rear))
               {
                    st[rear][9]=st[front][9]+1;
                    rear++;
               }
           }
       }
       front++;
   }
   return 0;
}
int main()
{
    while(cin>>st[1][0])
    {
        for(int i=1;i<9;i++) cin>>st[1][i];
        st[1][9]=0;
        for(int i=0;i<9;i++) cin>>cup[i];
        int ans=bfs();
        if(ans>0) cout<<st[ans][9]<<endl;
        else cout<<-1<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值