八数码问题实现(裸BFS版+A*版)C++实现

八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每一个棋子上标有1至8的某一数字,不一样棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子能够移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
所谓问题的一个状态就是棋子在棋盘上的一种摆法。棋子移动后,状态就会发生改变。解八数码问题实际上就是找出从初始状态到达目标状态所通过的一系列中间过渡状态。ios

人工智能课的做业。感受一点都不智能。。
算法核心是bfs hash用的是康拓展开
输入是第一行是初始状态,第二行是终止状态,空格用0表示。
012
345 ———> 012345678
678
一些测试数据:
012345678
102345678web

103425678
123405678算法

123045678
123405678svg

123475608
123405678函数

123450678
123405678测试

234150768
123456780ui

结果:
最少步数为:1
路径为:r人工智能

最少步数为:1
路径为:dspa

最少步数为:1
路径为:rcode

最少步数为:1
路径为:u

最少步数为:1
路径为:l

最少步数为:19
路径为:ullddrurdllurdruldr

下面贴两个版本的代码

裸BFS版
参考kuangbin的HDU1043的代码写的,由于本身原先写了一个以为很丑,仍是大佬的姿式比较优美。

#include "cstdio"
#include "queue"
#include "cstring"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "cmath"
#include "vector"
using namespace std;
const int MAXN=1000000;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
bool vis[MAXN];//标记
string path;
int aim;//123456780对应的康拖展开的hash值
int aimmap[3][3];
int mymove[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
char indexs[5]="udlr";//正向搜索
int cantor(int s[])//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0;i<9;i++)
    {
        int num=0;
        for(int j=i+1;j<9;j++)
            if(s[j]<s[i])num++;
        sum+=(num*fac[9-i-1]);
    }
    return sum+1;
}
struct Node
{
    int s[9];
    int loc;//“0”的位置
    int status;//康拖展开的hash值
    int step;//统计步数 也用做gx
    int hx;
    string path;//路径
    void gethx()
    {
        int temp=0;
        for(int i=0;i<9;i++)
        {
            int cur_x=i/3;
            int cur_y=i%3;
            for(int j=0;j<3;j++)
            {
                for(int k=0;k<3;k++)
                {
                    if(aimmap[j][k]==s[i])
                    {
                        temp+=abs(j-cur_x)+abs(k-cur_y);
                    }

                }
            }
        }
        hx=temp;
    }
};
struct cmp //优先队列须要的排序函数,升序
{
    bool operator()(Node &a,Node &b)
    {
        int aa=a.hx+a.step;
        int bb=b.hx+b.step;
        return aa>bb;
    }
};
Node ncur;
bool bfs()
{
    memset(vis,false,sizeof(vis));
    Node cur,next;
    priority_queue<Node,vector<Node>,cmp>q;
    ncur.gethx();
    q.push(ncur);
    while(!q.empty())
    {
        cur=q.top();
        q.pop();
        if(cur.status==aim)
        {
            path=cur.path;
            return true;
        }
        int x=cur.loc/3;
        int y=cur.loc%3;
        for(int i=0;i<4;i++)
        {
            int tx=x+mymove[i][0];
            int ty=y+mymove[i][1];
            if(tx<0||tx>2||ty<0||ty>2)continue;
            next=cur;
            next.loc=tx*3+ty;
            next.s[cur.loc]=next.s[next.loc];
            next.s[next.loc]=0;
            next.status=cantor(next.s);
            if(!vis[next.status])
            {
                next.step++;
                ncur.gethx();
                vis[next.status]=true;
                next.path=next.path+indexs[i];

                if(next.status==aim)
                {
                    cout<<"最少步数为:"<<next.step<<endl;
                    path=next.path;
                    return true;
                }
                q.push(next);
                next.step--;
            }
        }
    }
    return false;
}
int main()
{
    char start;
    int myaim[9];
    while(1)
    {
        ncur.step=0;
        for(int i=0;i<9;i++)
        {
            cin>>start;
            if(start=='0')
                ncur.loc=i;
            ncur.s[i]=start-'0';
        }
        ncur.status=cantor(ncur.s);
        for(int i=0;i<9;i++)
        {
            char to;
            cin>>to;
            myaim[i]=to-'0';
            int cur_x=i/3;
            int cur_y=i%3;
            aimmap[cur_x][cur_y]=to-'0';
        }
        aim=cantor(myaim);
        ncur.status=cantor(ncur.s);
        if(bfs())
        {
            cout<<"路径为:"<<path<<endl;
        }
        else cout<<"无解"<<endl;
        cout<<endl<<endl;
    }
    return 0;
}

A*版
h(x)用的是到当前状态的步数
g(x)是用的当前每一个格子中的数到最终位置的曼哈顿距离(街区距离)的和,而后优先队列维护一下就行了。

#include "cstdio"
#include "queue"
#include "cstring"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "cmath"
#include "vector"
using namespace std;
const int MAXN=1000000;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
bool vis[MAXN];//标记
string path;
int aim;//123456780对应的康拖展开的hash值
int aimmap[3][3];
int mymove[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
char indexs[5]="udlr";//正向搜索
int cantor(int s[])//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0;i<9;i++)
    {
        int num=0;
        for(int j=i+1;j<9;j++)
            if(s[j]<s[i])num++;
        sum+=(num*fac[9-i-1]);
    }
    return sum+1;
}
struct Node
{
    int s[9];
    int loc;//“0”的位置
    int status;//康拖展开的hash值
    int step;//统计步数 也用做gx
    int hx;
    string path;//路径
    void gethx()
    {
        int temp=0;
        for(int i=0;i<9;i++)
        {
            int cur_x=i/3;
            int cur_y=i%3;
            for(int j=0;j<3;j++)
            {
                for(int k=0;k<3;k++)
                {
                    if(aimmap[j][k]==s[i])
                    {
                        temp+=abs(j-cur_x)+abs(k-cur_y);
                    }

                }
            }
        }
        hx=temp;
    }
};
struct cmp //优先队列须要的排序函数,升序
{
    bool operator()(Node &a,Node &b)
    {
        int aa=a.hx+a.step;
        int bb=b.hx+b.step;
        return aa>bb;
    }
};
Node ncur;
bool bfs()
{
    memset(vis,false,sizeof(vis));
    Node cur,next;
    priority_queue<Node,vector<Node>,cmp>q;
    ncur.gethx();
    q.push(ncur);
    while(!q.empty())
    {
        cur=q.top();
        q.pop();
        if(cur.status==aim)
        {
            path=cur.path;
            return true;
        }
        int x=cur.loc/3;
        int y=cur.loc%3;
        for(int i=0;i<4;i++)
        {
            int tx=x+mymove[i][0];
            int ty=y+mymove[i][1];
            if(tx<0||tx>2||ty<0||ty>2)continue;
            next=cur;
            next.loc=tx*3+ty;
            next.s[cur.loc]=next.s[next.loc];
            next.s[next.loc]=0;
            next.status=cantor(next.s);
            if(!vis[next.status])
            {
                next.step++;
                ncur.gethx();
                vis[next.status]=true;
                next.path=next.path+indexs[i];

                if(next.status==aim)
                {
                    cout<<"最少步数为:"<<next.step<<endl;
                    path=next.path;
                    return true;
                }
                q.push(next);
                next.step--;
            }
        }
    }
    return false;
}
int main()
{
    char start;
    int myaim[9];
    while(1)
    {
        ncur.step=0;
        for(int i=0;i<9;i++)
        {
            cin>>start;
            if(start=='0')
                ncur.loc=i;
            ncur.s[i]=start-'0';
        }
        ncur.status=cantor(ncur.s);
        for(int i=0;i<9;i++)
        {
            char to;
            cin>>to;
            myaim[i]=to-'0';
            int cur_x=i/3;
            int cur_y=i%3;
            aimmap[cur_x][cur_y]=to-'0';
        }
        aim=cantor(myaim);
        ncur.status=cantor(ncur.s);
        if(bfs())
        {
            cout<<"路径为:"<<path<<endl;
        }
        else cout<<"无解"<<endl;
        cout<<endl<<endl;
    }
    return 0;
}