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;
}
- 把一个字符串变成图中的一个节点
- 以后有空格的地方可以变成