注:本文为半转载文章,原文链接为A_L_A_N的博文 总之比原文充实…
/*
Name: A*
Copyright: CQHFBZ
Author: YJ
Date: 2020/01/26 18:45
Description: 咕咕咕,一个让人咕的寻路算法...
*/
1 M e e t A ∗ 1\space Meet\space A* 1 Meet A∗
A
∗
A*
A∗是一个让人咕咕咕的优秀的寻路
o
r
or
or搜索算法
T A TA TA的中心思路是贪心, B F S BFS BFS,和预估函数
T
A
TA
TA的时间复杂度是
θ
(
\theta(
θ(出的题能过
)
)
)并不是我懒
2 D o A ∗ 2\space Do\space A* 2 Do A∗
此处有一地图:
绿色代表起点( A A A),红色代表终点( B B B),蓝色代表障碍(即不可行的状态),小方格代表一种状态(起点,终点皆为一种状态)
那我们开始搜索c
定义两个列表 O p e n L i s t , C l o s e L i s t OpenList, CloseList OpenList,CloseList代表待搜索列表和已搜索列表( H a s h Hash Hash映射也行)
1. 将起点 A A A加入 O p e n L i s t OpenList OpenList
2. 寻找起点 A A A周围可以到达的格子,将他们加入 O p e n L i s t OpenList OpenList,并将他们的父节点设为起点 A A A
3. 将起点 A A A弹出 O p e n L i s t OpenList OpenList并加入 C l o s e L i s t CloseList CloseList
如图,描有浅绿色的边的格子代表在 O p e n L i s t OpenList OpenList里面的格子
描有浅蓝色的边的格子代表在 C l o s e L i s t CloseList CloseList里面的格子
我们要比出那个格子最靠谱,接下来,就是A*算法最核心的公式 F = G + H F=G+H F=G+H
路人:一个三元一次不等式…
其中, F F F代表的经过方格 X X X的预估距离
G G G代表从起点 A A A到方格 X X X的实际距离
H H H代表从方格 X X X到终点 B B B的预估距离
注意1:计算出的 F F F值得尽量小于而又尽量接近实际距离,这跟一个好的 H H H密切相关
如上图,我们为了方便讲解,将横着的一步的距离设为
10
10
10,斜着的一步的距离设为
14
14
14,且斜走时旁边不能有障碍我不会告诉你我是为了抠图…
每个已遍历方格的左下角是 G G G,右下角是 H H H,左上角是 F F F
4. 可见 F F F值最小的是起点 A A A的左边方格 C C C,将 T A TA TA周围可到达的格子(除障碍物与在 C l o s e L s i t CloseLsit CloseLsit内的格子)加入 O p e n L i s t OpenList OpenList…
停!
我们这时候就要来分类讨论了:
4.1. 某方格 D D D已经在 O p e n L i s t OpenList OpenList里面了
这时候我们就要与前面的 G G G值作比较,取最小的 F F F值,更新路径(即父节点)
4.2. 某方格 D D D还不在 O p e n L i s t OpenList OpenList里面了
那还不加入…
如上图,那 C C C方格的上面 D D D方格来讲,他的新 G G G值是 10 + 10 = 20 10+10=20 10+10=20,而原 G G G值是 14 14 14,所以要保留原来路径,不要绕路
5. 现在我们开始寻找 O p e n L i s t OpenList OpenList中寻找"最靠谱"的方格,但我们发现 C C C上面和下面的F值都是 54 54 54,我们这时候就只能靠运气,随便选一个,就拿下面方格举例,称他为 D D D,将 T A TA TA的周围顶点如 4.1 , 4.2 4.1, 4.2 4.1,4.2一样做处理
注意2:方格 D D D并不是由方格 C C C走来的, T A TA TA是由 T A TA TA的父节点 A A A走来的,这是一个很常见的错误?(顺便说一下,我上一句谈到 C C C只因为让读者知道位置,而非表达一个递进关系…)
完成后如图:
看看与你是否想的一样
…
…
( N N N个…)
最后,我们会得到两种结果:
N N N.1. 终点 B B B已加入 O p e n L i s t OpenList OpenList,查找成功
那么就沿着父节点向前搜索,直到起点,再反向输出路径:
⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ \Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓
N N N.2. O p e n L i s t OpenList OpenList已经为空,查找失败
return -1;
3 s u m m a r y A ∗ 3\space summary\space A* 3 summary A∗
上伪代码(本人第一次写伪代码,写的不好可以揍我可以喷我,但不可以揍我,因为我是练习时长两年半的个人
O
i
e
r
Oier
Oier:
Y
J
YJ
YJ…):
//A_star伪代码//
//前置芝士: 指针//
/*****定义*****/
struct node {
pair<int, int> pos;
int G, H, F;
int father;//0~7, 从上面开始顺时针标号
} Start, End;
int way[2][8] = {{1, 0}, {1, -1}, {0, -1}, {-1, -1}, ......};
vector<node*> OpenList;
vector<node*> CloseList;
/*****定义*****/
/*****过程*****/
node* InList(list<node*> &L, node* find);//寻找find是否在L里面(有返回指针,没返回NULL)
node* MinF();//找出带有最小F值的node指针
bool CanGo(pair<int, int> posx, int wayi);//判断可不可以到达
int GetG(node* X, int wayi);//求G
int GetH(node* X, node* E);//一个优秀的函数
bool AStar(node* S, node* E) {
S -> G = 0;
S -> H = S -> F = Get_H(S, E);
S -> father = -1;
S加入OpenList;
while (OpenList不为空) {
node* X = MinF();
删除OpenList里面的X;
X加入CloseList;
for (i : 0 ~ 7) {
node* Y = 新的node;
if (一大堆要求 and CanGo(X -> pos, i) and InList(CloseList, Y) == NULL) {
if (Y是E) return 1;
求Y的GHF;
node* InListY = InList(OpenList, Y);
if (InList == NULL) {
Y -> father = i;
Y加入OpenList;
}
else {
if (Y -> G < InListY -> G) {
更改InListY的G, F, father;
}
}
}
}
}
return 0;
}
vector<node*> GetPath(node* S, node* E) {
vector<node*> path;
//读者们请自行思考
return path;
}
/*****过程*****/
/*****main*****/
int main() {
//读者们请自行思考
return 0;
}
489.第k短路
题目描述
给定一张N个点(编号1,2…N),M条边的有向图,求从起点S到终点T的第K短路的长度,路径允许重复经过点或边。
注意:每条最短路中至少要包含一条边。
输入格式
第一行包含两个整数N和M。
接下来M行,每行包含三个整数A,B和L,表示点A与点B之间存在有向边,且边长为L。
最后一行包含三个整数S,T和K,分别表示起点S,终点T和第K短路。
输出格式
输出占一行,包含一个整数,表示第K短路的长度,如果第K短路不存在,则输出“-1”。
样例
样例输入
2 2
1 2 5
2 1 4
1 2 2
样例输出
14
数据范围与提示
1 <= n <= 1000, 0 <= m <= 100000
1 <= a, b <= N, 1 <= T(权值)<= 100
1 <= s, t <= N, 1 <= k <= 1000
由于路径可以重复,所以 O p e n L i s t , C l o s e L i s t OpenList,CloseList OpenList,CloseList统统不要, H H H函数就是由终点道各点的路径( S P F A SPFA SPFA即可)
c o d e : code: code:
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 3e3 + 10;
template <typename T>
inline void read(T &x) {
x = 0;
T ff = 1, ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
ff = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
}
template <typename T>
inline void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n, m, s, t, k;
int f[MAXN], vis[MAXN];
int lin[MAXN], tot = 0, linc[MAXN], totc = 0;
struct edge {
int y, v, next;
} a[MAXN], e[MAXN];
struct node {
int pos, H, G;
bool operator < (node a) const { return a.H + a.G < H + G; }
};
inline void add(int xx, int yy, int vv) {
a[++tot].y = yy;
a[tot].v = vv;
a[tot].next = lin[xx];
lin[xx] = tot;
}
inline void addc(int xx, int yy, int vv) {
e[++totc].y = yy;
e[totc].v = vv;
e[totc].next = linc[xx];
linc[xx] = totc;
}
void SPFA() {
queue<int> q;
memset(f, 0x3f, sizeof(f));
memset(vis, false, sizeof(vis));
q.push(t);
f[t] = 0;
vis[t] = true;
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = false;
for (int i = lin[x], y; i; i = a[i].next) {
if (f[y = a[i].y] > f[x] + a[i].v) {
f[y] = f[x] + a[i].v;
if (!vis[y]) {
vis[y] = true;
q.push(y);
}
}
}
}
}
int astar() {
priority_queue<node> q;
if (f[s] == INF)
return -1;
int ts[MAXN];
node tmp, h;
h.pos = s;
h.H = 0;
h.G = 0;
q.push(h);
while (!q.empty()) {
node x = q.top();
q.pop();
ts[x.pos]++;
if (ts[x.pos] == k && x.pos == t)
return x.G;
if (ts[x.pos] > k)
continue;
for (int i = linc[x.pos]; i; i = e[i].next) {
tmp.pos = e[i].y;
tmp.H = f[e[i].y];
tmp.G = x.G + e[i].v;
q.push(tmp);
}
}
return -1;
}
int main() {
read(n);
read(m);
for (int i = 1; i <= m; ++i) {
int u, v, w;
read(u);
read(v);
read(w);
add(v, u, w);
addc(u, v, w);
}
read(s);
read(t);
read(k);
if (s == t)
++k;
SPFA();
write(astar());
return 0;
}