AcWing 179.八数码

算法思路

本算法实际上也是BFS的一种应用,但是朴素的BFS搜索会导致需要搜索的状态过多从而发生TLE或者MLE。为了解决这种问题故采用了A*算法

估计函数

A*算法中一个关键的部分便是估计函数。通过估计函数使得算法可以找到一个接近理想情况的最佳路径。通常情况下一个可用的估计函数必须满足估计值小于最小值,本题的估计函数选择了各个点到其最终位置的曼哈顿距离之和。

A*算法使用一个小根堆代替了BFS中的队列,每次从小根堆中取出一个期望距离最短的点进行扩展,其中期望距离=当前点距离起点的距离+当前点到终点的估计距离

算法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <string>
#include <vector>

using namespace std;

#define PIS pair<int, string>

int has_no_result(string s)
{
int sum = 0;
for (int i = 0; i < s.size(); ++i)
{
for (int j = i + 1; j < s.size(); ++j)
{
if (s[i] == 'x' || s[j] == 'x') continue;
sum += (s[i] > s[j]);
}
}

return sum & 1;
}

int f(string s)
{
int sum = 0;
for (int i = 0; i < s.size(); ++i)
{
if (s[i] == 'x') continue;
int num = s[i] - '0';
int x = i % 3;
int y = i / 3;
int acx = (num - 1) % 3;
int acy = (num - 1) / 3;
sum += (abs(x - acx) + abs(y - acy));
}

return sum;
}

void bfs(string s)
{
unordered_map<string, int> dist;
unordered_map<string, pair<char, string>> prev;
priority_queue<PIS, vector<PIS>, greater<PIS>> heap;

heap.push({f(s), s});
dist[s] = 0;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
char op[] = {'d', 'u', 'r', 'l'};
string final = "12345678x";

while(!heap.empty())
{
auto t = heap.top();
heap.pop();

string state = t.second;
if (state == final) break;
int d = t.first;

int x = 0, y = 0;
for (int i = 0; i < state.size(); ++i)
{
if (state[i] == 'x')
{
x = i % 3;
y = i / 3;
break;
}
} // compute position

string dummy = state;
for (int i = 0; i < 4; ++i)
{
int nx = x + dx[i], ny = y + dy[i];
if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) continue;
swap(dummy[y * 3 + x], dummy[ny * 3 + nx]);
if (!dist.count(dummy) || dist[dummy] > dist[state] + 1)
{
dist[dummy] = dist[state] + 1;
heap.push({f(dummy) + dist[dummy], dummy});
prev[dummy] = {op[i], state};
}

dummy = state;
}
}

string res;
while(final != s)
{
res += prev[final].first;
final = prev[final].second;
}

reverse(res.begin(), res.end());
cout << res;
}

int main()
{
string s;
for (int i = 0; i < 9; ++i)
{
char t;
cin >> t;
s += t;
}

if (has_no_result(s))
{
cout << "unsolvable";
return 0;
}

bfs(s);
}

AcWing 179.八数码
http://anyin233.github.io/2022/01/26/AcWing-179-八数码/
Author
anyin233
Posted on
January 26, 2022
Licensed under