c++ 八数码问题增强版

题目描述

三行三列的数组,其元素值为0至8的数。现有如下的变换规则:

1: 将0与上面一行元素对换

2:将0与下面一行元素对换

3:将0与左面一行元素对换

4:将0与右面一行元素对换

如果已知一个三行三列元素的初始情况,问最少需几次变换,能变换为指定的一种情况?

输入

包括六行的数据,每行有三个以空格分隔的数字。 前三行为原始状态 后三行为目标状态

输出

若能在20次以内(包括20)变换得到目标状态的数组,输出最少的变换次数; 若不能在20次以内(包括20)变换得到目标状态的数组,输出No solution!

样例输入

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

样例输出

10

Hint

(None)

AC代码

#include<iostream>
#include <string.h> 
using namespace std;
struct Point//结构体
{
    int a[3][3];
    int step;
};
Point s,t,q[50000];
int f,e;
bool used[9][9][9][9][9][9][9][9];//used[][][][][][][][]是
Point gen(Point u,int type)//这个函数的主要内容就是枚举操作一遍所有的规则 跟 "倒水.cpp" 很相似
{
    int x,y;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if(u.a[i][j]==0)
            {
                x=i,y=j;
                break;
            }
    Point v=u;
    v.step=u.step+1;
    if(type==1&&x>0)//枚举第1种情况
        swap(v.a[x][y],v.a[x-1][y]);//交换上面一行元素
    else if(type==2&&x<2)//枚举第2种情况
        swap(v.a[x][y],v.a[x+1][y]);//将0与下面一行元素对换
    else if(type==3&&y>0)//枚举第3种情况
        swap(v.a[x][y],v.a[x][y-1]);//将0与左面一行元素对换
    else if(type==4&&y<2)//枚举第4种情况
        swap(v.a[x][y],v.a[x][y+1]);//将0与右面一行元素对换
    else
        v.step=-1;//如果交换不到指定的位置,就返回-1
    return v;
}
bool cmp(Point u,Point v)//比较两个结构体是否相同,相同为True 不同为False
{
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if(u.a[i][j]!=v.a[i][j])
                return 0;
    return 1;
}
int main()
{
    memset(used,0,sizeof(used));//used是
    for(int i=0;i<3;i++)//输入初始矩阵
        for(int j=0;j<3;j++)
           cin>> s.a[i][j];
    for(int i=0;i<3;i++)//输入期望矩阵
        for(int j=0;j<3;j++)
            cin>>t.a[i][j];
    if(cmp(s,t)==1)//如果他们一样就不用移动
    {
        cout<<0<<endl;//输出0步
        return 0;//退出
    }
    s.step=0;//初始化
    f=1,e=1;//f出队  e入队
    q[1]=s;//把s入队
    used[s.a[0][0]][s.a[0][1]][s.a[0][2]][s.a[1][0]][s.a[1][1]][s.a[1][2]][s.a[2][0]][s.a[2][1]]=1;//把初始矩阵除了5以外的都标为已使用
    while(f<=e)//防止越界
    {
        Point u=q[f++];//u是选定的元素
        for(int i=1;i<=4;i++)//像4个方向拓展
        {
            Point v=gen(u,i);//v是由u按题目上的规则拓展而来的
            if(v.step==-1) continue;//如果无法到达
            if(v.step>20) continue;//如果大于20步
            if(cmp(v,t)==1)//如果和预期的矩阵一样,就输出
            {
                cout<<v.step<<endl;//输出
                return 0;
            }
            if(v.step==20) continue;//如果等于20步
            if (used[v.a[0][0]][v.a[0][1]][v.a[0][2]][v.a[1][0]][v.a[1][1]][v.a[1][2]][v.a[2][0]][v.a[2][1]]==1)//如果初始矩阵除了5以外的都走过
                continue;
            e++;//入队下标+1
            q[e]=v;//入队
            used[v.a[0][0]][v.a[0][1]][v.a[0][2]][v.a[1][0]][v.a[1][1]][v.a[1][2]][v.a[2][0]][v.a[2][1]]=1;//把移完之后的状态保存,设为已经出现过 将来不能再出现 
        }
    }
    cout<<"No solution!"<<endl;//无解
    return 0;//返回
}