JPS+(Jump point search plus)寻路算法

JPS+(Jump point search plus)寻路算法

接上文 JPS(jump point search)寻路算法

JPS+ 是在 Jps 的基础上对地图进行了预处理,将数据记录在节点上

JPS 是运行时计算节点在某个方向上的跳点
JPS+ 预处理则是将 每个节点每个方向上的跳点、障碍信息记录,在运行时,不需要经过计算,直接获取某个方向上的跳点,节省大量时间和空间,提升计算速度

JPS+ 地图预处理
前提条件
1:地图必须是静态的,预处理时和运行时地图必须是一样的,不对在运行时添加、删除、修改节点状态
2:预处理需要每个节点存储一些数据,对内存占用较大
3:预处理需要时间较长,地图内每个节点都要进行数据处理,时间复杂度为 O(n*n),n 为节点个数

用 8 个数值,分别记录节点八个方向上:跳点、墙(障碍、边界)的距离

预处理
一:跳点、障碍预处理
初始节点 8 个方向上记录的值均为 0

第一步:对每个节点的八个方向进行跳点的可达性判断,并记录好跳点直线可达性
水平、垂直方向 距离 n 步 是跳点,则此方向记录 abs(n),如果没有跳点记录 0
斜向 距离 (n, n) 的节点是跳点,则此方向记录 abs(n),如果没有跳点记录 0

第二步:对节点的八个方向上,记录值还是 0 的方向上移动1步后碰到障碍(或边界)则记为0,
如果移动 n+1 步后会碰到障碍(或边界)的数据记为负数距离 -n

处理好的每个节点记录数据如下所示
2、3、0
-3、N、5
-4、0、3

8 个方向数据的解释
节点 N:左上方斜向, 两步 的距离有跳点
节点 N:上方垂直向上, 三步 的距离有跳点
节点 N:右上方斜向, 是障碍物或者地图边界
节点 N:左侧水平向左,三步 的距离是墙
节点 N:右侧水平向右,五步 的距离是跳点
节点 N:左下方斜向, 四步 的距离是墙
节点 N:下方垂直向下,是障碍物或者地图边界
节点 N:右下方斜向, 三步 的距离是跳点

二:Goal Bounding 预处理
目标边界(Goal Bounding)不是一种搜索算法,而是一种对搜索空间进行修减的方法,主要的原理是通过离线预处理搜索空间,实时运行搜索算法时,利用预先计算的数据来减少寻找目标所需要考虑的节点数量

Goal Bounding 也是需要节点存储 8 个方向的数据,每个数据 表示一个矩形区域如 Rect
Rect.min 是矩形区域的最小位置
Rect.max 是矩形区域的最大位置

关于 Goal Bounding 预处理的具体方法,可以查看相关论文、博客

做好了地图的预处理之后,我们就可以使用JPS+算法了。
大致思路与JPS算法相同,不过这次有了预处理的数据,我们可以更快的进行直线搜索和斜向搜索。

在某个搜索方向上有:
在获取某个方向上跳点数据前,需要通过 Goal Bounding 方法 WithinBoundingBox(n,dir, goal)判断节点此方向上是否包含目标节点,如果不包含则直接舍弃这个方向
1.对于正数距离 n(意味着距离跳点 n 格),我们可以直接将n步远的节点作为跳点添加进openlist
2.对于0距离(意味着一步都不可移动),我们无需在该方向搜索;
3.对于负数距离 -n(意味着距离边界或障碍 n 格),我们直接将n步远的节点进行一次跳点判断(有可能满足跳点的三个条件,不过得益于预处理的数据,这步也可以很快完成)。

理论知识如上

我上传的项目中
一:跳点、障碍预处理 部分已经添加了

二:Goal Bounding 预处理 部分还未添加

项目中 JPS+ 功能还不能正常使用

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Jump Point Search算法是一种近年来提出的新型寻路算法,能够在路网数据中快速跳过大量的不可行区域,极大地提高了寻路效率。以下是一个简单的C++实现示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <cmath> using namespace std; const int MAXN = 100; const int INF = 0x3f3f3f3f; int n, m; // 路网数据的行列数 int sx, sy, ex, ey; // 起点和终点的坐标 int map[MAXN][MAXN]; // 路网数据 int dis[MAXN][MAXN]; // 距离起点的距离 bool vis[MAXN][MAXN]; // 是否已经访问过 int dir[8][2] = {{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}}; // 方向数组 struct Node { int x, y, f, g, h; // 坐标、f值、g值、h值 bool operator<(const Node& a) const { return f > a.f; // 优先队列为小根堆,f值小的优先级高 } }; bool is_valid(int x, int y) { return x >= 0 && x < n && y >= 0 && y < m && map[x][y] == 0; } vector<pair<int, int>> get_successors(int x, int y, int dx, int dy) { vector<pair<int, int>> successors; if (dx != 0 && dy != 0) { if (is_valid(x + dx, y + dy) && (!is_valid(x + dx, y) || !is_valid(x, y + dy))) { successors.push_back({x + dx, y + dy}); } if (is_valid(x + dx, y) && !is_valid(x, y + dy)) { successors.push_back({x + dx, y}); successors.push_back({x + dx, y + dy}); } if (is_valid(x, y + dy) && !is_valid(x + dx, y)) { successors.push_back({x, y + dy}); successors.push_back({x + dx, y + dy}); } } else { if (dx == 0) { if (is_valid(x, y + dy)) { successors.push_back({x, y + dy}); if (!is_valid(x + 1, y)) successors.push_back({x + 1, y + dy}); if (!is_valid(x - 1, y)) successors.push_back({x - 1, y + dy}); } } else { if (is_valid(x + dx, y)) { successors.push_back({x + dx, y}); if (!is_valid(x, y + 1)) successors.push_back({x + dx, y + 1}); if (!is_valid(x, y - 1)) successors.push_back({x + dx, y - 1}); } } } return successors; } void jump(int x, int y, int dx, int dy) { int nx = x + dx, ny = y + dy; if (!is_valid(nx, ny)) return; if (nx == ex && ny == ey) { dis[nx][ny] = dis[x][y] + 1; return; } if (vis[nx][ny]) return; vis[nx][ny] = true; int g = dis[x][y] + 1; int h = abs(nx - ex) + abs(ny - ey); int f = g + h; priority_queue<Node> pq; pq.push({nx, ny, f, g, h}); while (!pq.empty()) { Node u = pq.top(); pq.pop(); int x = u.x, y = u.y; if (vis[x][y]) continue; vis[x][y] = true; dis[x][y] = u.g; vector<pair<int, int>> successors = get_successors(x, y, dx, dy); for (auto& s : successors) { int nx = s.first, ny = s.second; int g = dis[x][y] + 1; int h = abs(nx - ex) + abs(ny - ey); int f = g + h; pq.push({nx, ny, f, g, h}); } } } void JPS() { memset(dis, INF, sizeof(dis)); memset(vis, false, sizeof(vis)); dis[sx][sy] = 0; vis[sx][sy] = true; priority_queue<Node> pq; pq.push({sx, sy, abs(ex - sx) + abs(ey - sy), 0, abs(ex - sx) + abs(ey - sy)}); while (!pq.empty()) { Node u = pq.top(); pq.pop(); int x = u.x, y = u.y; if (x == ex && y == ey) return; for (int i = 0; i < 8; i++) { int dx = dir[i][0], dy = dir[i][1]; if ((dx == 0 || dy == 0) || (is_valid(x + dx, y) && is_valid(x, y + dy))) { jump(x, y, dx, dy); } } } } int main() { cin >> n >> m >> sx >> sy >> ex >> ey; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> map[i][j]; } } JPS(); cout << dis[ex][ey] << endl; return 0; } ``` 这段代码实现了Jump Point Search算法的基本框架,包括预处理跳跃点、递归跳跃、状态转移和优先队列的使用。需要注意的是,Jump Point Search算法的预处理过程比较耗时,因此它更适用于需要多次寻路的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值