算法005:A*搜索
A*搜索算法
概述
A*(读作"A-star")搜索算法是一种广泛使用的路径搜索和图遍历算法,由Peter Hart、Nils Nilsson和Bertram Raphael在1968年首次提出。A算法是Dijkstra算法的扩展,通过引入启发式函数来指导搜索方向,从而更高效地找到最短路径。A算法在游戏AI、机器人导航、路径规划等领域有着广泛的应用。
算法描述
A*算法结合了Dijkstra算法的保证最优性和贪心算法的效率,通过评估函数 f(n)=g(n)+h(n)f(n) = g(n) + h(n)f(n)=g(n)+h(n) 来选择下一个要处理的节点:
- 初始化:将起始节点加入开放列表,设置其 ggg 值为0,hhh 值为启发式估计值
- 选择节点:从开放列表中选择 fff 值最小的节点
- 扩展节点:将当前节点从开放列表移到关闭列表
- 检查目标:如果当前节点是目标节点,则重建路径并返回
- 处理邻居:对于每个邻居节点:
- 计算新的 ggg 值
- 如果找到更好的路径,更新邻居节点的 ggg 值和 fff 值
- 如果邻居不在开放列表中,将其加入
- 重复:重复步骤2-5直到找到目标或开放列表为空
评估函数
A*算法的核心是评估函数 f(n)=g(n)+h(n)f(n) = g(n) + h(n)f(n)=g(n)+h(n):
- g(n)g(n)g(n):从起始节点到当前节点 nnn 的实际路径成本
- h(n)h(n)h(n):从当前节点 nnn 到目标节点的估计成本(启发式函数)
- f(n)f(n)f(n):从起始节点通过当前节点到目标节点的估计总成本
步骤详解
- 创建开放列表(Open List)和关闭列表(Closed List)
- 将起始节点加入开放列表
- 当开放列表不为空:
- 从开放列表中选择 fff 值最小的节点
- 如果该节点是目标节点,重建路径并返回
- 将该节点移到关闭列表
- 对于该节点的每个邻居:
- 如果邻居在关闭列表中,跳过
- 计算通过当前节点到邻居的新 ggg 值
- 如果邻居不在开放列表中,或找到更好的 ggg 值:
- 更新邻居的 ggg 值和 fff 值
- 设置邻居的前驱节点为当前节点
- 如果邻居不在开放列表中,将其加入
数学基础
时间复杂度
- 最坏情况:O(bd)O(b^d)O(bd) - 其中 bbb 是分支因子,ddd 是解的深度
- 平均情况:取决于启发式函数的质量,通常优于Dijkstra算法
空间复杂度
- 空间复杂度:O(bd)O(b^d)O(bd) - 需要存储所有可能路径的节点
数学分析
A*算法的正确性依赖于启发式函数的性质:
可容性(Admissibility):启发式函数 h(n)h(n)h(n) 必须满足 h(n)≤h∗(n)h(n) \leq h^*(n)h(n)≤h∗(n),其中 h∗(n)h^*(n)h∗(n) 是从节点 nnn 到目标节点的实际最短距离。
一致性(Consistency):对于任意节点 nnn 和其邻居 mmm,满足 h(n)≤w(n,m)+h(m)h(n) \leq w(n, m) + h(m)h(n)≤w(n,m)+h(m),其中 w(n,m)w(n, m)w(n,m) 是从 nnn 到 mmm 的边权重。
当启发式函数满足可容性时,A算法保证找到最短路径;当满足一致性时,A算法在第一次访问到节点时就找到了最优路径,无需再次访问。
实现
Python实现
import heapq
import math
class Node:
def __init__(self, position, parent=None):
self.position = position
self.parent = parent
self.g = 0 # 从起点到当前节点的实际代价
self.h = 0 # 从当前节点到终点的估计代价
self.f = 0 # f = g + h
def __eq__(self, other):
return self.position == other.position
def __lt__(self, other):
return self.f < other.f
def __hash__(self):
return hash(self.position)
def heuristic(a, b, method='euclidean'):
"""
启发式函数
参数:
a: 起点坐标
b: 终点坐标
method: 启发式方法 ('euclidean', 'manhattan', 'chebyshev')
返回:
估计距离
"""
if method == 'euclidean':
return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2)
elif method == 'manhattan':
return abs(a[0] - b[0]) + abs(a[1] - b[1])
elif method == 'chebyshev':
return max(abs(a[0] - b[0]), abs(a[1] - b[1]))
else:
raise ValueError("不支持的启发式方法")
def astar(grid, start, end, heuristic_method='euclidean'):
"""
A*算法实现
参数:
grid: 二维网格,0表示可通过,1表示障碍物
start: 起点坐标 (x, y)
end: 终点坐标 (x, y)
heuristic_method: 启发式方法
返回:
最短路径和路径长度
"""
# 创建节点对象
start_node = Node(start)
end_node = Node(end)
# 初始化开放列表和关闭列表
open_list = []
closed_list = set()
# 将起点加入开放列表
heapq.heappush(open_list, start_node)
# 网格尺寸
rows = len(grid)
cols = len(grid[0])
# 可能的移动方向(8方向)
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
while open_list:
# 获取f值最小的节点
current_node = heapq.heappop(open_list)
# 如果到达终点
if current_node.position == end_node.position:
path = []
current = current_node
while current:
path.append(current.position)
current = current.parent
return path[::-1], current_node.g
# 将当前节点加入关闭列表
closed_list.add(current_node)
# 检查所有可能的移动
for direction in directions:
# 计算邻居位置
neighbor_pos = (current_node.position[0] + direction[0],
current_node.position[1] + direction[1])
# 检查边界
if (neighbor_pos[0] < 0 or neighbor_pos[0] >= rows or
neighbor_pos[1] < 0 or neighbor_pos[1] >= cols):
continue
# 检查障碍物
if grid[neighbor_pos[0]][neighbor_pos[1]] == 1:
continue
# 创建邻居节点
neighbor = Node(neighbor_pos, current_node)
# 如果邻居在关闭列表中,跳过
if neighbor in closed_list:
continue
# 计算移动成本(对角线移动成本为sqrt(2),直线移动为1)
move_cost = math.sqrt(2) if direction[0] != 0 and direction[1] != 0 else 1
neighbor.g = current_node.g + move_cost
# 计算启发式值
neighbor.h = heuristic(neighbor_pos, end, heuristic_method)
neighbor.f = neighbor.g + neighbor.h
# 检查是否需要更新邻居节点
in_open = False
for open_node in open_list:
if open_node == neighbor and open_node.g <= neighbor.g:
in_open = True
break
if not in_open:
heapq.heappush(open_list, neighbor)
# 没有找到路径
return None, float('infinity')
# 示例网格
grid = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 1, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
]
# 使用示例
start = (0, 0)
end = (9, 9)
path, distance = astar(grid, start, end, 'euclidean')
print(f"从 {start} 到 {end} 的最短路径:")
for i, pos in enumerate(path):
if i > 0:
print(" -> ", end="")
print(pos, end="")
print(f"\n路径长度: {distance:.2f}")
C++实现
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <unordered_set>
#include <algorithm>
using namespace std;
struct Node {
pair<int, int> position;
Node* parent;
double g; // 从起点到当前节点的实际代价
double h; // 从当前节点到终点的估计代价
double f; // f = g + h
Node(pair<int, int> pos, Node* p = nullptr) : position(pos), parent(p), g(0), h(0), f(0) {}
bool operator==(const Node& other) const {
return position == other.position;
}
bool operator<(const Node& other) const {
return f < other.f;
}
};
struct NodeHash {
size_t operator()(const Node* node) const {
return hash<int>()(node->position.first) ^ hash<int>()(node->position.second);
}
};
struct NodeEqual {
bool operator()(const Node* a, const Node* b) const {
return a->position == b->position;
}
};
double heuristic(pair<int, int> a, pair<int, int> b, const string& method) {
if (method == "euclidean") {
return sqrt(pow(a.first - b.first, 2) + pow(a.second - b.second, 2));
} else if (method == "manhattan") {
return abs(a.first - b.first) + abs(a.second - b.second);
} else if (method == "chebyshev") {
return max(abs(a.first - b.first), abs(a.second - b.second));
} else {
throw invalid_argument("不支持的启发式方法");
}
}
pair<vector<pair<int, int>>, double> astar(const vector<vector<int>>& grid,
pair<int, int> start,
pair<int, int> end,
const string& heuristic_method) {
// 创建节点对象
Node* start_node = new Node(start);
Node* end_node = new Node(end);
// 优先队列(最小堆)
priority_queue<Node*, vector<Node*>, greater<Node*>> open_list;
unordered_set<Node*, NodeHash, NodeEqual> closed_list;
// 将起点加入开放列表
open_list.push(start_node);
// 网格尺寸
int rows = grid.size();
int cols = grid[0].size();
// 可能的移动方向(8方向)
vector<pair<int, int>> directions = {
{-1, -1}, {-1, 0}, {-1, 1},
{0, -1}, {0, 1},
{1, -1}, {1, 0}, {1, 1}
};
while (!open_list.empty()) {
// 获取f值最小的节点
Node* current_node = open_list.top();
open_list.pop();
// 如果到达终点
if (current_node->position == end_node->position) {
vector<pair<int, int>> path;
Node* current = current_node;
while (current) {
path.push_back(current->position);
current = current->parent;
}
reverse(path.begin(), path.end());
// 清理内存
delete start_node;
delete end_node;
while (!open_list.empty()) {
delete open_list.top();
open_list.pop();
}
return {path, current_node->g};
}
// 将当前节点加入关闭列表
closed_list.insert(current_node);
// 检查所有可能的移动
for (const auto& direction : directions) {
// 计算邻居位置
pair<int, int> neighbor_pos = {
current_node->position.first + direction.first,
current_node->position.second + direction.second
};
// 检查边界
if (neighbor_pos.first < 0 || neighbor_pos.first >= rows ||
neighbor_pos.second < 0 || neighbor_pos.second >= cols) {
continue;
}
// 检查障碍物
if (grid[neighbor_pos.first][neighbor_pos.second] == 1) {
continue;
}
// 创建邻居节点
Node* neighbor = new Node(neighbor_pos, current_node);
// 如果邻居在关闭列表中,跳过
if (closed_list.find(neighbor) != closed_list.end()) {
delete neighbor;
continue;
}
// 计算移动成本
double move_cost = (direction.first != 0 && direction.second != 0) ? sqrt(2) : 1;
neighbor->g = current_node->g + move_cost;
// 计算启发式值
neighbor->h = heuristic(neighbor_pos, end, heuristic_method);
neighbor->f = neighbor->g + neighbor->h;
// 检查是否需要更新邻居节点
bool in_open = false;
vector<Node*> open_nodes;
while (!open_list.empty()) {
open_nodes.push_back(open_list.top());
open_list.pop();
}
for (auto node : open_nodes) {
if (*node == *neighbor && node->g <= neighbor->g) {
in_open = true;
open_list.push(node);
break;
}
open_list.push(node);
}
if (!in_open) {
open_list.push(neighbor);
} else {
delete neighbor;
}
}
}
// 清理内存
delete start_node;
delete end_node;
// 没有找到路径
return {{}, -1};
}
int main() {
// 示例网格
vector<vector<int>> grid = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 0, 0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
{0, 1, 1, 1, 1, 0, 1, 0, 1, 0},
{0, 0, 0, 0, 1, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 1, 1, 1, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 1, 0}
};
// 使用示例
pair<int, int> start = {0, 0};
pair<int, int> end = {9, 9};
auto result = astar(grid, start, end, "euclidean");
auto path = result.first;
double distance = result.second;
cout << "从 (" << start.first << "," << start.second << ") 到 ("
<< end.first << "," << end.second << ") 的最短路径:" << endl;
for (size_t i = 0; i < path.size(); i++) {
if (i > 0) {
cout << " -> ";
}
cout << "(" << path[i].first << "," << path[i].second << ")";
}
cout << "\n路径长度: " << distance << endl;
return 0;
}
变体和优化
1. 简化的A*算法(4方向移动)
def astar_4direction(grid, start, end, heuristic_method='manhattan'):
"""
只支持4方向移动的A*算法
参数:
grid: 二维网格
start: 起点坐标
end: 终点坐标
heuristic_method: 启发式方法
返回:
最短路径和路径长度
"""
start_node = Node(start)
end_node = Node(end)
open_list = []
closed_list = set()
heapq.heappush(open_list, start_node)
rows = len(grid)
cols = len(grid[0])
# 4方向移动
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
while open_list:
current_node = heapq.heappop(open_list)
if current_node.position == end_node.position:
path = []
current = current_node
while current:
path.append(current.position)
current = current.parent
return path[::-1], current_node.g
closed_list.add(current_node)
for direction in directions:
neighbor_pos = (current_node.position[0] + direction[0],
current_node.position[1] + direction[1])
if (neighbor_pos[0] < 0 or neighbor_pos[0] >= rows or
neighbor_pos[1] < 0 or neighbor_pos[1] >= cols):
continue
if grid[neighbor_pos[0]][neighbor_pos[1]] == 1:
continue
neighbor = Node(neighbor_pos, current_node)
neighbor.g = current_node.g + 1 # 4方向移动成本为1
neighbor.h = heuristic(neighbor_pos, end, heuristic_method)
neighbor.f = neighbor.g + neighbor.h
if neighbor in closed_list:
continue
in_open = False
for open_node in open_list:
if open_node == neighbor and open_node.g <= neighbor.g:
in_open = True
break
if not in_open:
heapq.heappush(open_list, neighbor)
return None, float('infinity')
2. Theta算法(基于A的路径优化)
def theta_star(grid, start, end, heuristic_method='euclidean'):
"""
Theta*算法:基于A*的路径优化算法
参数:
grid: 二维网格
start: 起点坐标
end: 终点坐标
heuristic_method: 启发式方法
返回:
最短路径和路径长度
"""
start_node = Node(start)
end_node = Node(end)
open_list = []
closed_list = set()
heapq.heappush(open_list, start_node)
rows = len(grid)
cols = len(grid[0])
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
while open_list:
current_node = heapq.heappop(open_list)
if current_node.position == end_node.position:
path = []
current = current_node
while current:
path.append(current.position)
current = current.parent
return path[::-1], current_node.g
closed_list.add(current_node)
for direction in directions:
neighbor_pos = (current_node.position[0] + direction[0],
current_node.position[1] + direction[1])
if (neighbor_pos[0] < 0 or neighbor_pos[0] >= rows or
neighbor_pos[1] < 0 or neighbor_pos[1] >= cols):
continue
if grid[neighbor_pos[0]][neighbor_pos[1]] == 1:
continue
neighbor = Node(neighbor_pos, current_node)
# 检查直线路径
if current_node.parent:
parent_pos = current_node.parent.position
if line_of_sight(grid, parent_pos, neighbor_pos):
# 可以直接从父节点跳转到邻居
move_cost = heuristic(parent_pos, neighbor_pos, 'euclidean')
new_g = current_node.parent.g + move_cost
else:
move_cost = math.sqrt(2) if direction[0] != 0 and direction[1] != 0 else 1
new_g = current_node.g + move_cost
else:
move_cost = math.sqrt(2) if direction[0] != 0 and direction[1] != 0 else 1
new_g = current_node.g + move_cost
neighbor.g = new_g
neighbor.h = heuristic(neighbor_pos, end, heuristic_method)
neighbor.f = neighbor.g + neighbor.h
if neighbor in closed_list:
continue
in_open = False
for open_node in open_list:
if open_node == neighbor and open_node.g <= neighbor.g:
in_open = True
break
if not in_open:
heapq.heappush(open_list, neighbor)
return None, float('infinity')
def line_of_sight(grid, pos1, pos2):
"""
检查两点之间是否有直线路径(无障碍物)
参数:
grid: 二维网格
pos1: 起点坐标
pos2: 终点坐标
返回:
是否有直线路径
"""
x1, y1 = pos1
x2, y2 = pos2
dx = abs(x2 - x1)
dy = abs(y2 - y1)
x_step = 1 if x2 > x1 else -1
y_step = 1 if y2 > y1 else -1
x, y = x1, y1
if dx > dy:
error = dx / 2.0
while x != x2:
if grid[x][y] == 1:
return False
error -= dy
if error < 0:
y += y_step
error += dx
x += x_step
else:
error = dy / 2.0
while y != y2:
if grid[x][y] == 1:
return False
error -= dx
if error < 0:
x += x_step
error += dy
y += y_step
return True
3. 分层A算法(Hierarchical A)
def hierarchical_astar(grid, start, end, levels=3):
"""
分层A*算法实现
参数:
grid: 二维网格
start: 起点坐标
end: 终点坐标
levels: 分层层数
返回:
最短路径和路径长度
"""
# 创建不同分辨率的网格
grids = create_hierarchical_grids(grid, levels)
# 从最高层开始搜索
for level in range(levels - 1, -1, -1):
current_grid = grids[level]
current_start = get_coarse_position(start, level, grid, current_grid)
current_end = get_coarse_position(end, level, grid, current_grid)
# 在当前层进行A*搜索
path, distance = astar_4direction(current_grid, current_start, current_end, 'manhattan')
if path is not None:
# 如果找到了路径,细化路径
refined_path = refine_path(path, level, grid)
if refined_path:
return refined_path, len(refined_path) - 1
return None, float('infinity')
def create_hierarchical_grids(grid, levels):
"""
创建不同分辨率的网格
参数:
grid: 原始网格
levels: 层数
返回:
不同分辨率的网格列表
"""
grids = [grid]
for level in range(1, levels):
# 将网格分辨率降低为原来的1/2
rows = len(grids[-1]) // 2
cols = len(grids[-1][0]) // 2
new_grid = [[0 for _ in range(cols)] for _ in range(rows)]
for i in range(rows):
for j in range(cols):
# 检查2x2区域是否有障碍物
has_obstacle = False
for di in range(2):
for dj in range(2):
if grids[-1][2*i + di][2*j + dj] == 1:
has_obstacle = True
break
if has_obstacle:
break
new_grid[i][j] = 1 if has_obstacle else 0
grids.append(new_grid)
return grids
def get_coarse_position(pos, level, original_grid, coarse_grid):
"""
获取在指定层级的坐标
参数:
pos: 原始坐标
level: 层级
original_grid: 原始网格
coarse_grid: 当前层级的网格
返回:
在当前层级的坐标
"""
scale = 2 ** level
return (pos[0] // scale, pos[1] // scale)
def refine_path(path, level, original_grid):
"""
细化路径
参数:
path: 粗略路径
level: 当前层级
original_grid: 原始网格
返回:
细化后的路径
"""
if level == 0:
return path
refined_path = []
for i in range(len(path) - 1):
start = path[i]
end = path[i + 1]
# 在两个粗略节点之间进行细化
refined_segment = refine_segment(start, end, level, original_grid)
if refined_segment:
if i > 0:
refined_path.extend(refined_segment[1:])
else:
refined_path.extend(refined_segment)
return refined_path
def refine_segment(start, end, level, grid):
"""
细化单个路径段
参数:
start: 起点坐标
end: 终点坐标
level: 当前层级
grid: 原始网格
返回:
细化后的路径段
"""
scale = 2 ** level
fine_start = (start[0] * scale, start[1] * scale)
fine_end = (end[0] * scale, end[1] * scale)
# 在细粒度网格中寻找路径
fine_grid = create_fine_grid(grid, scale)
path, _ = astar_4direction(fine_grid, fine_start, fine_end, 'manhattan')
return path
应用场景
A*算法广泛应用于:
- 游戏AI:角色寻路、NPC导航
- 机器人导航:自主移动机器人的路径规划
- GPS导航:车辆导航系统的路线规划
- 网络路由:数据包的最优路径选择
- 图像处理:图像分割和目标识别
优点和缺点
优点
- 最优性保证:在可容性启发式函数下保证找到最短路径
- 高效性:通过启发式函数减少搜索空间
- 灵活性:可以适应各种不同的启发式函数
- 可扩展性:可以扩展到多维空间和复杂场景
- 实用性:在许多实际应用中表现优异
缺点
- 内存消耗大:需要存储大量节点
- 启发式依赖:性能高度依赖于启发式函数的质量
- 最坏情况性能:在某些情况下可能退化为穷举搜索
- 动态环境适应性差:对于频繁变化的场景需要重新计算
- 实现复杂:相比简单搜索算法实现更复杂
性能比较
| 算法 | 时间复杂度 | 空间复杂度 | 最优性 | 适用场景 |
|---|---|---|---|---|
| A* (启发式) | O(bd)O(b^d)O(bd) | O(bd)O(b^d)O(bd) | 是(可容性) | 需要最优路径 |
| Dijkstra | O((V+E)logV)O((V + E) \log V)O((V+E)logV) | O(V+E)O(V + E)O(V+E) | 是 | 非负权重图 |
| BFS | O(V+E)O(V + E)O(V+E) | O(V)O(V)O(V) | 是(无权重图) | 无权重图 |
| DFS | O(V+E)O(V + E)O(V+E) | O(V)O(V)O(V) | 否 | 深度优先搜索 |
| Greedy Best-First | O(bd)O(b^d)O(bd) | O(bd)O(b^d)O(bd) | 否 | 快速搜索 |
实际应用示例
示例1:游戏中的角色寻路
def game_pathfinding_example():
"""
游戏中的角色寻路示例
"""
# 创建游戏地图
game_map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 1, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
]
# 角色位置和目标位置
player_pos = (0, 0)
target_pos = (9, 9)
# 使用A*算法寻找路径
path, distance = astar(game_map, player_pos, target_pos, 'euclidean')
print(f"角色从 {player_pos} 移动到 {target_pos} 的路径:")
for i, pos in enumerate(path):
if i > 0:
print(" -> ", end="")
print(pos, end="")
print(f"\n移动距离: {distance:.2f}")
# 模拟角色移动
print("\n角色移动过程:")
for i, pos in enumerate(path):
print(f"步骤 {i+1}: 移动到位置 {pos}")
if i < len(path) - 1:
next_pos = path[i + 1]
dx = next_pos[0] - pos[0]
dy = next_pos[1] - pos[1]
if dx == -1 and dy == -1:
print(" 方向: 左上")
elif dx == -1 and dy == 0:
print(" 方向: 上")
elif dx == -1 and dy == 1:
print(" 方向: 右上")
elif dx == 0 and dy == -1:
print(" 方向: 左")
elif dx == 0 and dy == 1:
print(" 方向: 右")
elif dx == 1 and dy == -1:
print(" 方向: 左下")
elif dx == 1 and dy == 0:
print(" 方向: 下")
elif dx == 1 and dy == 1:
print(" 方向: 右下")
game_pathfinding_example()
示例2:机器人路径规划
def robot_pathfinding_example():
"""
机器人路径规划示例
"""
# 工厂地图
factory_map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 1, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
]
# 机器人起始位置和目标位置
robot_start = (0, 0)
robot_target = (9, 9)
# 使用不同启发式函数的A*算法
print("使用欧几里得启发式函数:")
path_euclid, dist_euclid = astar(factory_map, robot_start, robot_target, 'euclidean')
print(f"路径长度: {dist_euclid:.2f}")
print("\n使用曼哈顿启发式函数:")
path_manhattan, dist_manhattan = astar(factory_map, robot_start, robot_target, 'manhattan')
print(f"路径长度: {dist_manhattan:.2f}")
print("\n使用切比雪夫启发式函数:")
path_chebyshev, dist_chebyshev = astar(factory_map, robot_start, robot_target, 'chebyshev')
print(f"路径长度: {dist_chebyshev:.2f}")
# 比较性能
print(f"\n性能比较:")
print(f"欧几里得: {len(path_euclid)} 步, {dist_euclid:.2f} 单位")
print(f"曼哈顿: {len(path_manhattan)} 步, {dist_manhattan:.2f} 单位")
print(f"切比雪夫: {len(path_chebyshev)} 步, {dist_chebyshev:.2f} 单位")
# 选择最佳路径
best_path = path_euclid
best_dist = dist_euclid
if dist_manhattan < best_dist:
best_path = path_manhattan
best_dist = dist_manhattan
if dist_chebyshev < best_dist:
best_path = path_chebyshev
best_dist = dist_chebyshev
print(f"\n选择的最佳路径:")
for i, pos in enumerate(best_path):
if i > 0:
print(" -> ", end="")
print(pos, end="")
print(f"\n总距离: {best_dist:.2f}")
robot_pathfinding_example()
示例3:分层A*算法应用
def hierarchical_astar_example():
"""
分层A*算法应用示例
"""
# 大型地图
large_map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
start = (0, 0)
end = (14, 14)
print("使用标准A*算法:")
path, distance = astar(large_map, start, end, 'euclidean')
print(f"路径长度: {distance:.2f}, 路径点数: {len(path)}")
print("\n使用分层A*算法:")
h_path, h_distance = hierarchical_astar(large_map, start, end, 3)
print(f"路径长度: {h_distance:.2f}, 路径点数: {len(h_path)}")
print("\n性能比较:")
print(f"标准A*: {len(path)} 个节点")
print(f"分层A*: {len(h_path)} 个节点")
print(f"节点数减少: {((len(path) - len(h_path)) / len(path) * 100):.1f}%")
hierarchical_astar_example()
结论
A*算法是路径搜索领域中最重要和最广泛使用的算法之一。它通过结合Dijkstra算法的保证最优性和贪心算法的效率,在保证找到最短路径的同时,显著提高了搜索效率。
A算法的核心优势在于其灵活的启发式函数设计,可以根据不同的应用场景选择合适的启发式方法。从游戏AI到机器人导航,从GPS系统到网络路由,A算法的身影无处不在。
随着技术的发展,A算法也衍生出了许多变体和优化版本,如Theta算法、分层A算法等,这些算法在特定场景下能够提供更好的性能。A算法的成功不仅在于其解决问题的能力,更在于它所体现的启发式搜索思想,这一思想已经成为人工智能和算法设计中的重要原则。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)