八数码问题

                                                                                                八数码问题

题意:

         编号为1~8的8个正方形滑块被摆成3行3列(有一个格子留空),如下图所示       每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中,而他原来的位置   就成为了新的空格。如果无法到达目标局面,则输出-1 。

      2         6        4    
    1       3    7
         5     8

移到后
          8                 1                5     
          7             3           6
          4             2 

样例输入:

2 6 4 1 3 7 0 5 8

8 1 5 7 3 6 4 0 2

样例输出:

31

【分析】

           八数码很像我们小时候玩的拼图游戏,就是把打乱的图拼成指定形状。可以       把题看成求最短路径问题,只是在原来的基础上增加了不少难度,增加了每步的       判断0的位置,和0的移动,还要保存每步后的移动结果,判断重复。数组要开大

    因为数据移动最大可达到9!个(9!是多少,啊我忘了,反正几十万),还要定       义长度为9的数组,要来保存移动时的数据情况。

【代码】

<span style="background-color: rgb(51, 255, 255);">#include<stdio.h>
#include<string.h>
#include<set>
using namespace std;
typedef int State[9];       // 储存表格
const int maxstate = 1000000;   // 最大1000000步
State st[maxstate],goal;        // 定义goal[9],定义st[maxstate][9]
int dist[maxstate];     // 存储步数

const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
set<int>vis;
void init_lookup_table()
{
    vis.clear();
}
int try_to_insert(int s)
{
    int v=0;
    for(int i=0;i<9;i++)
        v=v*10+st[s][i];    // 将现在的阵列生成一个9位数
    if(vis.count(v))        // 查找是否用过
        return 0;
    vis.insert(v);          // 插入set容器,用于标记
    return 1;
}
// 广搜
int bfs()
{
    init_lookup_table();
    int front=1,rear=2;
    while(front<rear)
    {
        State& s=st[front];  // 将现在的位置保存到s中
        if(memcmp(goal,s,sizeof(s))==0) // 判断与目标是否相等
            return front;
        int z;
        for(z=0;z<9;z++)
            if(!s[z])       // 查找0的位置
                break;
        int x=z/3,y=z%3;    // 0的x,y坐标
        for(int d=0;d<4;d++)
        {
            int newx=x+dx[d];   // 0可以的的点
            int newy=y+dy[d];
            int newz=newx*3+newy;   // 0可移动到点(newx,newy)处,newz表示在串的第几个
            //printf("newz=%d,z=%d\n",newz,z);
            if(newx>=0&&newx<3&&newy>=0&&newy<3)    // 判断是否越界
            {
                State& t=st[rear];          // 定义t[9]
                memcpy(&t,&s,sizeof(s));    // 将s的数据赋给t
                // 0的移动,两位置互换
                t[newz]=s[z];   // 移动0到(newx,newy)处
                t[z]=s[newz];   // (newx,newy)的数据移动原来0的位置
               // printf("t[newz]=%d  t[z]=%d,z=%d\n",t[newz],t[z],z);
                dist[rear]=dist[front]+1;   // 储存步数
                if(try_to_insert(rear))
                    rear++;                 // 尾指针后移
            }
        }
        front++;
    }
    return 0;
}

int main()
{
    for(int i=0;i<9;i++)
        scanf("%d",&st[1][i]);
    for(int i=0;i<9;i++)
        scanf("%d",&goal[i]);
    int ans=bfs();  // 返回头地址
    if(ans>0)
        printf("%d\n",dist[ans]);  // 输出存储的步数
    else printf("-1\n");        // 如果找不到输出-1
    return 0;
}</span>
代码注释有不当之处或有更好的代码,麻烦大神留言!

你可能感兴趣的:(八数码问题)