八数码及其变式

引言

八数码问题的关键有两点:

  • 将整张图作为bfs的一个状态
  • 如何进行状态转移

代码上的技巧主要有:

  • 使用map代替dist数组,改dist[ed] == 0x3f3f3f3fmp.count(ed) == 0
  • 学会矩阵转数组的方法
  • 学会使用vector存图

下面将从以上两个角度分析下面题目。

AcWing 845. 八数码

题目描述

18x分布在以下3×3的网格中:

1 2 3
x 4 6
7 5 8

每次操作可将x与其上下左右四个数字中的一个进行位置交换,问最少操作多少次可以达到以下状态?

1 2 3
4 5 6
7 8 x

解题思路

状态表示
3×3的矩阵展开为string,作为整张图的表示
状态转移

  • 首先将字母在string中的位置'u'对应到矩阵中的位置

x = u / 3, y = u % 3

  • 枚举四个方向进行新的矩阵坐标计算,swap方法得到新状态

注意该题状态非常多,需要使用unordered_map

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <queue>

using namespace std;

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
unordered_map<string, int> mp;
queue<string> q;

int main()
{
    string ed = "12345678x";
    string st = "xxxxxxxxx";
    for(int i = 0; i < 9; i ++){
        char c; cin >> c;
        st[i] = c;
    }
    
    q.push(st); mp[st] = 0;
    while(q.size()){
        auto t = q.front(); q.pop();
        
        if(t == ed){
            printf("%d\n", mp[t]);
            return 0;
        }
        
        int u;
        for(int i = 0; i < 9; i ++)
            if(t[i] == 'x') u = i;
        int tx = u / 3, ty = u % 3;

        for(int i = 0; i < 4; i ++){
            int x = tx + dx[i], y = ty + dy[i];
            if(x < 0 || x > 2 || y < 0 || y > 2) continue;
            string s = t;
            swap(s[u], s[3 * x + y]);
            if(mp.count(s)) continue;
            mp[s] = mp[t] + 1;
            q.push(s);
        }
    }
    
    puts("-1");
    return 0;
}

D - 8 Puzzle on Graph

题目描述

该题与上题的不同之处在于:

  • 对于可以移动的方向,通过M条边的无向图给出
  • 每次只能与数字'9'交换位置

数据范围

0M36

解题思路

状态表示
string表示目前各个拼图的位置状态
状态转移
枚举9所在位置的所有出边,swap方法得到新状态

注意不需要使用unordered_map进行加速

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <queue>

using namespace std;

const int N = 15;

vector<int> vec[N];
queue<string> q;
map<string, int> mp;
int m;

int main()
{
    scanf("%d", &m);
    while(m --){
        int x, y; scanf("%d%d", &x, &y);
        vec[x].push_back(y);
        vec[y].push_back(x);
    }

    string st = "0999999999";
    for(int i = 1; i <= 8; i ++){
        int x; scanf("%d", &x);
        st[x] = i + '0';
    }

    q.push(st); mp[st] = 0;
    while(q.size())
    {
        auto t = q.front(); q.pop();

        int v = 0;
        for(int i = 0; i <= 9; i ++)
            if(t[i] == '9') v = i;

        for(auto p : vec[v]){
            string s = t;
            swap(s[p], s[v]);
            if(mp.count(s)) continue;
            mp[s] = mp[t] + 1;
            q.push(s);
        }
    }

    string ed = "0123456789";
    if(mp.count(ed) == 0) puts("-1");
    else printf("%d\n", mp[ed]);

    return 0;
}

posted @   小菜珠的成长之路  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示