Loading

洛谷P1379 八数码难题(BFS)

洛谷P1379 八数码难题

​ 八数码问题就是在 \(3\times 3\) 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格,我们用 0 来表示。给出一个初始局面,给出一个目标局面。请问从初始局面到目标局面的最小移动次数是多少。关于八数码问题的移动,洛谷中的Tips有提示。

思路:

​ 最小操作次数,我们把移动看成一次状态的转移,那么这就是一个最短路问题。将题意抽象为:每次 0 可以与其周围的任一棋子交换位置,我们直接用BFS来写就可以了。状态可以用一维的字符串来表示,但是转移的时候是需要借助到这个棋盘的二维结构的,看代码领会一下。

代码:

​ 体会一维和二维之间的转换。

#include <bits/stdc++.h>

using namespace std;
int d[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
string ans = "123804765"; //题面给的

int bfs(string s)
{
    queue<string> q;
    unordered_map<string, int> dis; //记录最少操作次数并判重,将二维的矩阵压到一维,可以降低时空复杂度。
    
    q.push(s);
    dis[s] = 0;
    
    while (q.size())
    {
        string t = q.front();
        q.pop();
        
        if(t == ans)    return dis[t];
        
        int distance = dis[t];
        int k = t.find('0');
        int x = k / 3, y = k % 3; //把一维的字符串展开成二维的矩阵
        
        for(int i = 0; i < 4; i++)
        {
            int xx = x + d[i][0], yy = y + d[i][1];
            if(xx >= 0 && xx < 3 && yy >= 0 && yy < 3)
            {
                swap(t[k], t[xx * 3 + yy]);
                if(!dis.count(t)) //若这个状态没有出现过
                {
                    q.push(t);
                    dis[t] = distance + 1;   
                }
                swap(t[k], t[xx * 3 + yy]); //回溯
            }
        }
    }
    return -1; //int函数中要防止未定义的行为。虽然题目明确说明了都可以到达目标状态,但是写代码要有鲁棒性
}

int main()
{
    string s;
    cin >> s;
    cout << bfs(s);
}
posted @ 2022-12-23 18:06  DM11  阅读(67)  评论(0编辑  收藏  举报