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) 来选择下一个要处理的节点:

  1. 初始化:将起始节点加入开放列表,设置其 ggg 值为0,hhh 值为启发式估计值
  2. 选择节点:从开放列表中选择 fff 值最小的节点
  3. 扩展节点:将当前节点从开放列表移到关闭列表
  4. 检查目标:如果当前节点是目标节点,则重建路径并返回
  5. 处理邻居:对于每个邻居节点:
    • 计算新的 ggg
    • 如果找到更好的路径,更新邻居节点的 ggg 值和 fff
    • 如果邻居不在开放列表中,将其加入
  6. 重复:重复步骤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):从起始节点通过当前节点到目标节点的估计总成本

步骤详解

  1. 创建开放列表(Open List)和关闭列表(Closed List)
  2. 将起始节点加入开放列表
  3. 当开放列表不为空:
    • 从开放列表中选择 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) 是从 nnnmmm 的边权重。

当启发式函数满足可容性时,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*算法广泛应用于:

  1. 游戏AI:角色寻路、NPC导航
  2. 机器人导航:自主移动机器人的路径规划
  3. GPS导航:车辆导航系统的路线规划
  4. 网络路由:数据包的最优路径选择
  5. 图像处理:图像分割和目标识别

优点和缺点

优点

  1. 最优性保证:在可容性启发式函数下保证找到最短路径
  2. 高效性:通过启发式函数减少搜索空间
  3. 灵活性:可以适应各种不同的启发式函数
  4. 可扩展性:可以扩展到多维空间和复杂场景
  5. 实用性:在许多实际应用中表现优异

缺点

  1. 内存消耗大:需要存储大量节点
  2. 启发式依赖:性能高度依赖于启发式函数的质量
  3. 最坏情况性能:在某些情况下可能退化为穷举搜索
  4. 动态环境适应性差:对于频繁变化的场景需要重新计算
  5. 实现复杂:相比简单搜索算法实现更复杂

性能比较

算法 时间复杂度 空间复杂度 最优性 适用场景
A* (启发式) O(bd)O(b^d)O(bd) O(bd)O(b^d)O(bd) 是(可容性) 需要最优路径
Dijkstra O((V+E)log⁡V)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算法的成功不仅在于其解决问题的能力,更在于它所体现的启发式搜索思想,这一思想已经成为人工智能和算法设计中的重要原则。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐