Fork me on GitHub

八数码

Acwing845.八数码

这种题有个特征就是状态图

迅速判重

原来3×3的矩阵需要\(9!×9!\)次检查,每个状态要和\(9!\)对比

康托展开

每个状态和康托的哈希函数进行判重

时间复杂度:

\[O(n!n!) →O(n!n^2) \]

long int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}
bool Cantor(int str[], int n)
{
    long result = 0;
    for (int i = 0; i < n; i ++ )
    {
        int counted = 0;
        for (int j = i + 1; j < n; j ++ )
        {
            if (str[i] > str[j]) ++ counted;
        }
        result += counted * factory[n - i - 1];
    }
    if (!visited[result])
    {
        visited[result] = 1;
        return true;
    }
    return 0;
}

用隐时图的概念

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <unordered_map>
using namespace std;
queue<string> q;
unordered_map<string, int> d;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};


int bfs(string state)
{
    q.push(state);
    d[state] = 0;
    string end = "12345678x";
    while(!q.empty())
    {
        auto t = q.front();
        q.pop();

        int distance = d[t];
        if (end == t) return distance;
        int cor = t.find('x');
        int x = cor / 3;
        int y = cor % 3;
        for (int i = 0; i < 4; i ++ ) 
        {
            int dx = x + dir[i][0]; 
            int dy = y + dir[i][1];
            if(dx >= 0 && dx < 3 && dy >= 0 && dy < 3)
            {
                swap(t[cor], t[dx * 3 + dy]);
                if(!d.count(t))
                {
                    d[t] = distance + 1;
                    q.push(t);
                }
                swap(t[cor], t[dx * 3 + dy]);
            }

        } 
    }
    return -1;
}

int main()
{
    char s[2];  // 用字符数组存储字符串时需要多开一位,用来存字符串的结束符'\0'
    string start;
    for (int i = 0; i < 9; i ++ )
    {
        cin >> s;
        start += *s;
    }
    cout << bfs(start) << endl;

}
  1. 把一个字符串变成图中的一个节点
  2. 以后有空格的地方可以变成
posted @ 2020-04-13 22:55  WalterJ726  阅读(173)  评论(0编辑  收藏  举报