经典的八数码问题

来源:互联网 发布:mac移动硬盘无法读取 编辑:程序博客网 时间:2024/06/06 01:40

问题描述:

在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。现在的问题是:对于指定的初始棋局和目标棋局,给出数码的移动序列。该问题称八数码难题或者重排九宫问题。


问题思路:

这可以看做是一个隐式图搜索问题,把每一次移动一格子的分布认为是一个状态图,空格记为0,并认为移动格子的时候,移动的是0这一个格子和另外的格子交换。我在这里使用典型的BFS算法来判断是否能到达目标状态,并且给出多少步。

#include<iostream>#include<algorithm>#include<cstring>#include<set>using namespace std;typedef int state[9];const int maxn=1000000;state st[maxn],goal;int dist[maxn];int front,rear;const int dx[]={-1,1,0,0};const int dy[]={0,0,-1,1};set<int> vis;int try_to_insert(int pos)//判断重复{    int tmp=0;    for(int i=0;i<9;i++) tmp=tmp*10+st[pos][i];//把状态图计算为一个9位的独一无二的数字存在set中    if(vis.count(tmp)) return 0;    vis.insert(tmp);    return 1;}int bfs(){    vis.clear();    front=1,rear=2;    while(front<rear)    {        state &s=st[front];        if(memcmp(goal,s,sizeof(s))==0) return front;        int i,j,x,y;        for(i=0;i<9;i++) if(s[i]==0) break;//找到0这一格所在位置,把状态的变化看作是0这一格的移动        x=i/3,y=i%3;        for(j=0;j<4;j++)        {            int newx=x+dx[j];            int newy=y+dy[j];            if(newx>=0&&newx<3&&newy>=0&&newy<3)            {                state &v=st[rear];                memcpy(&v,&s,sizeof(s));                v[x*3+y]=v[newx*3+newy];                v[newx*3+newy]=0;                dist[rear]=dist[front]+1;                if(try_to_insert(rear)) rear++;//判断是否出现重复状态            }        }        front++;    }}int main(){    for(int i=0;i<9;i++) cin>>st[1][i];    for(int i=0;i<9;i++) cin>>goal[i];    int d=bfs();    if(d>0) cout<<dist[d]<<endl;    else cout<<"-1"<<endl;    return 0;}

输入:

2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2

输出:

31


1 0
原创粉丝点击