A*算法小入门--八数码
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A*算法小入门--八数码相关的知识,希望对你有一定的参考价值。
A*算法初步详解
详细请看百度百科
最核心的估价函数:f(x) = g(x) + h(x)
g(x)
为从起点开始的距离函数,比如从起点开始走了多少步。h(x)
为当前位置到达终点的启发式搜索函数。根据题意进行变动。
h(x)的一般形态
一、求最短路问题时:
- 曼哈顿距离(只允许四个方向时):
计算曼哈顿距离的函数如下,这里的D是指两个相邻节点之间的移动代价,通常是一个固定的常数。
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy)
- 对角距离(允许八个方向时)
计算对角距离的函数如下,这里的D2指的是两个斜着相邻节点之间的移动代价。如果所有节点都正方形,则其值就是sqrt(D).
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
- 欧几里得距离(允许任何方向时)
就两点的直线距离:
二、求最短路变式问题时
实际上有很多题目并不是很严格的最短路问题,那么这种情况下视情况也可以用A* 算法,比如移动距离问题。
给定一图案要求移动到答案的最少操作次数,这时候 h(x) 可以用两幅图的不相同的程度来进行表示。
利用f(x)完成A*算法
A*算法必备的数据结构是一个最小堆,我们还需要自定义一个node结构体,里面重载最小堆的排序方式,排序方式一定按照估值函数
f
返回的大小进行。
当然和bfs类似,一般也需要进行去重。
话不多说,我们根据这些步骤用A*算法完成下面这道题目吧!
例题
解题代码
#include <algorithm>
#include <cstdio>
#include <queue>
#include <set>
using namespace std;
const int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
int fx, fy;
char ch;
struct matrix {//自定义matrix类型,重载<用于set判断
int a[5][5];
bool operator<(const matrix& x) const {
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
if (a[i][j] != x.a[i][j]) return a[i][j] < x.a[i][j];
return false;
}
} f, st;
int h(matrix a) {//h(x)函数
int ret = 0;
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
if (a.a[i][j] != st.a[i][j]) ret++;
return ret;
}
struct node { //node结构,记录走的步数,以及对应的图,重载<用估值函数进行最小堆的构建
matrix a;
int t;
bool operator<(const node& x) const { return t + h(a) > x.t + h(x.a); }
} x;
priority_queue<node> q; //搜索队列
set<matrix> s; //防止搜索队列重复
int main() {
st.a[1][1] = 1; //定义标准表
st.a[1][2] = 2;
st.a[1][3] = 3;
st.a[2][1] = 8;
st.a[2][2] = 0;
st.a[2][3] = 4;
st.a[3][1] = 7;
st.a[3][2] = 6;
st.a[3][3] = 5;
for (int i = 1; i <= 3; i++) //输入
for (int j = 1; j <= 3; j++) {
scanf(" %c", &ch);
f.a[i][j] = ch - '0';
}
q.push({f, 0});
while (!q.empty()) {
x = q.top();
q.pop();
if (!h(x.a)) { //判断是否与标准矩阵一致
printf("%d\\n", x.t);
return 0;
}
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
if (!x.a.a[i][j]) fx = i, fy = j; //找到0开始扩散
for (int i = 0; i < 4; i++) { //对四种移动方式分别进行搜索
int xx = fx + dx[i], yy = fy + dy[i];
if (1 <= xx && xx <= 3 && 1 <= yy && yy <= 3) {
swap(x.a.a[fx][fy], x.a.a[xx][yy]);
if (!s.count(x.a))
s.insert(x.a),
q.push({x.a, x.t + 1}); //这样移动后,将新的情况放入搜索队列中
swap(x.a.a[fx][fy], x.a.a[xx][yy]); //回溯,撤销操作
}
}
}
return 0;
}
以上是关于A*算法小入门--八数码的主要内容,如果未能解决你的问题,请参考以下文章