P1379 八数码难题

题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式
输入初始状态,一行九个数字,空格用0表示

输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例
输入 #1复制
283104765
输出 #1复制
4

#include 
#include 

using namespace std;

typedef int State[9];       //定义“State”类型
const int maxstate = 1000000;
State st[maxstate], goal = {
     1, 2, 3, 8, 0, 4, 7, 6, 5};       //距离数组
int dist[maxstate];
//打印,父亲编号数组int fa[maxstate];

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

void init_lookup_table();
int try_to_insert(int s);

//bfs,返回目标状态下的st数组下标
int bfs()
{
     
    //初始化查找表
    init_lookup_table();
    //不用下标0
    int front = 1, rear = 2;

    while(front < rear)
    {
     
        //引用
        State& s = st[front];
        //如果找到目标状态就return
        if(memcmp(goal, s, sizeof(s)) == 0)
            return front;

        int z;
        //找0的位置
        for(z = 0; z < 9; z++)
            if(!s[z])
                break;
        //定位z,(0-2)
        int x = z / 3, y = z % 3;

        for(int d = 0; d < 4; d++)
        {
     
            int newx = x + dx[d];
            int newy = y + dy[d];
            int newz = newx * 3 + newy;
            //判断移动是否合法
            if(newx >= 0 && newx < 3 && newy >=0 && newy < 3)
            {
     
                //拓展新节点
                State& t = st[rear];
                memcpy(&t, &s, sizeof(s));
                t[newz] = s[z];
                t[z] = s[newz];
                //更新新节点的距离值
                dist[rear] = dist[front] + 1;
                //如果成功插入查找表,修改队尾指针,若重复则下个覆盖当前表
                if(try_to_insert(rear))
                    rear++;
            }
        }
        front++;
    }
    return 0;
}

//Hash判断是否重复
const int hashsize = 1000003;
int head[hashsize], nextl[maxstate];

void init_lookup_table(){
     
    memset(head, 0, sizeof(head));
}
int hashf(State& s)
{
     
    int v = 0;
    //9个数转换成9位数
    for(int i = 0; i < 9; i++)
        v = v * 10 + s[i];
    //确保hash函数值是不超过hash表大小的非负整数
    return v % hashsize;
}

int try_to_insert(int s)
{
     
    int h = hashf(st[s]);
    //从表头开始查找链表
    int u = head[h];
    while(u){
     
        //找到了,插入失败
        if(memcmp(st[u], st[s], sizeof(st[s])) == 0)
            return 0;
        //顺着链表继续找
        u = nextl[u];
    }
    nextl[s] = head[h];
    head[h] = s;
    return 1;
}
//处理输入
void Inputf(){
     
    int start;
    int pow = 10;

    cin >> start;

    for(int i = 8; i >= 0; i--){
     
        st[1][i] = start % pow;
        start /= 10;
    }
}

int main()
{
     
    Inputf();

    // for(int i = 0; i < 9; i++)
    //     cout << st[1][i] << ' ';
    
    // cout << endl;
    
    // for(int i = 0; i < 9; i++)
    //     cin >> goal[i];

    int ans = bfs();

    if(ans > 0)
        cout << dist[ans] << endl;
    else
        cout << "-1" << endl;

    system("pause");

    return 0;
}

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

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