八数码(哈希表判重)

#include<iostream>
#include<cstring>
#include<stack>
#include<cstdio>
using namespace std;

const int maxn=1000000;//状态最大不超过9!,这里设置大一点

int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};

int st[maxn][9],goal[9];
int dis[maxn];//dis记录的就是步数
int head[maxn],next[maxn];
int par[maxn];//记录路径

//初始化,包括哈希查找表中用到的head的初始化
void init(){
    memset(dis,0,sizeof(dis));
    memset(head,0,sizeof(head));//head都初始化为0,其实就是起始每一个哈希值链表头指针均为空
    memset(next,0,sizeof(next));//next都初始化为0,其实就是起始每一个哈希值链表尾指针均为空
    memset(par,0,sizeof(par));
}

int hash_search(int a[9]){
    int v=0;
    for(int i=0;i<9;i++) v=v*10+a[i];
    return v%maxn;//这里假设了hash表长度也是maxn
}

bool try_to_insert(int rear){
    int h=hash_search(st[rear]);
    int u=head[h];//从具有同一个哈希值的一条链的头查起
    while(u){
        if(memcmp(st[u],st[rear],sizeof(st[rear]))==0) return false;
        u=next[u];
    }
    next[rear]=head[h];//把新来的rear永远指向具有同一哈希值的链表的表头
    head[h]=rear;//把新的哈希值的头指向此刻所在具有同一哈希值链表的表头
    return true;
}

int bfs(){
    init();
    int fro=1,rear=2;//bfs里,这里用到的暗含队列的头尾指针

    while(fro<rear){
        int flag=1;
        for(int i=0;i<9;i++){
            if(st[fro][i]!=goal[i]) {flag=0;break;}
        }
        if(flag) return fro;
        int z;
        for(int i=0;i<9;i++) if(st[fro][i]==0){z=i;break;}    //找到0所处的位置
                //上面这行坑死我了,我把fro写成1了,单步调试发现问题了……
        int x=z/3,y=z%3;
        for(int i=0;i<4;i++){
            int newx=x+dx[i];
            int newy=y+dy[i];
            int newz=newx*3+newy;
            if(newx>=0 && newx<3 && newy>=0 && newy<3){
                for(int i=0;i<9;i++) st[rear][i]=st[fro][i];//每走一步,更新一下st[rear]
                st[rear][newz]=st[fro][z];
                st[rear][z]=st[fro][newz];
                dis[rear]=dis[fro]+1;
                par[rear]=fro;
                if(try_to_insert(rear)) rear++;//如果成功插入哈希查找表,暗含队列指针后移一位
            }
        }
        fro++;
    }
    return 0;//所有路都走完一遍,无法达到目标
}

void print_path(int ans){
    cout<<"Start:"<<endl;
    for(int i=0;i<9;i++){
        cout<<st[1][i]<<" ";
        if((i+1)%3==0) cout<<endl;
    }
    cout<<"Goal:"<<endl;
    for(int i=0;i<9;i++){
        cout<<goal[i]<<" ";
        if((i+1)%3==0) cout<<endl;
    }
    cout<<endl;
    if(ans==0) {
        cout<<"There is no way to achieve our goal!"<<endl;
    }
    else{
        cout<<"The smallest number of steps is "<<dis[ans]<<". And we can go as follows!"<<endl;
        int u=par[ans];
        stack<int>sta;sta.push(ans);
        while((u!=1)){
            sta.push(u);
            u=par[u];
        }
        int step=0;
        while(!sta.empty()){
            cout<<"Step "<<++step<<endl;
            int v=sta.top();sta.pop();
            for(int i=0;i<9;i++){
                cout<<st[v][i]<<" ";
                if((i+1)%3==0) cout<<endl;
            }
        }
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    for(int i=0;i<9;i++) cin>>st[1][i];//从st[1]开始不从0开始,是为了在try_to_insert中u最终是0(链表尾指针为0)
    for(int i=0;i<9;i++) cin>>goal[i];
    int ans=bfs();
    print_path(ans);
    return 0;
}

posted @ 2018-05-05 19:34  MCQ  阅读(345)  评论(0编辑  收藏  举报