代码随想录算法训练营第62天|Floyd 算法精讲、A * 算法精讲 (A star算法)

1.Floyd 算法精讲

题目链接:Floyd 算法精讲
文档讲解: 代码随想录

本题是多源最短路,即求多个起点到多个终点的多条最短路径。Floyd算法对边的权值正负没有要求,都可以处理,其核心思想是动态规划。
动规五部曲:
(1)确定dp数组和下标
用grid存图,grid[i][j][k]表示节点 i 到节点 j 以[1,…,k] 集合为中间节点的最短距离
(2)递推关系式
分两种情况,一种是节点 i 到节点 j 的最短路径经过节点 k,grid[i][j][k] = grid[i][k][k-1] + grid[k][j][k-1];另一种情况,节点 i 到节点 j 的最短路径不经过节点 k,grid[i][j][k] = grip[i][j][k-1];两者取最小值
(3)初始化
刚开始初始化 k 是不确定的,如果赋值为1,那么不能知道节点 i 到节点 j 经过1个节点的最短距离,所以只能把 k 赋值为0,本题中节点0是无意义的,节点是从1到n。本题求的是最小值,所以其余值初始化为最大值
(4)遍历顺序
好比三维坐标,i,j是平层,而k是垂直向上的,遍历顺序是从底向上一层一层去遍历,所以遍历时 k 的for循环一定在最外面,这样才能一层一层去遍历,而 i 和 j 的先后顺序无所谓
(5)打印数组

#基于三维数组
n,m = map(int,input().split())
#创建三维数组
grid = [[[float('inf')] * (n+1) for _ in range(n+1)] for _ in range(n+1)]
#初始化
for _ in range(m):
    u,v,w = map(int,input().split())
    grid[u][v][0] = w 
    grid[v][u][0] = w 
#floyd
for k in range(1,n+1):
    for i in range(1,n+1):
        for j in range(1,n+1):
            grid[i][j][k] = min(grid[i][j][k-1],grid[i][k][k-1] + grid[k][j][k-1])
#输出结果
q = int(input())
for _ in range(q):
    start,end = map(int,input().split())
    if grid[start][end][n] == float('inf'):
        print(-1) 
    else:
        print(grid[start][end][n])
#基于二维数组
n,m = map(int,input().split())
grid = [[float('inf')] * (n+1) for _ in range(n+1)]
#初始化
for _ in range(m):
    u,v,w = map(int,input().split())
    grid[u][v] = w 
    grid[v][u] = w 
for k in range(1,n+1):
    for i in range(1,n+1):
        for j in range(1,n+1):
            grid[i][j] = min(grid[i][j],grid[i][k] + grid[k][j])
#输出结果
q = int(input())
for _ in range(q):
    start,end = map(int,input().split())
    if grid[start][end] == float('inf'):
        print(-1)
    else:
        print(grid[start][end])

2.A * 算法精讲 (A star算法)

题目链接:A * 算法精讲 (A star算法)
文档讲解: 代码随想录

bfs是没有目的性的一圈一圈搜索,而A*算法是有方向性的去搜索,通过启发式函数指引搜索方向。本题的图是无权网络状,使用欧氏距离来计算权值,对队列里的节点进行排序。

import heapq
direction = [[-2,1],[-1,2],[1,2],[2,1],[2,-1],[1,-2],[-1,-2],[-2,-1]]
maxx = 1001
#定义骑士类
class Knight:
    def __init__(self,x,y,g,h):
        self.x = x
        self.y = y
        self.g = g #从起点到该点的距离
        self.h = h #从该点到终点的距离
        self.f = g + h
    def __lt__(self,other):
        return self.f < other.f #小顶堆,按照f排序,统一不开根号可以提高精度
#计算欧式距离
def heuristic(k,b1,b2):
    return (k.x - b1) ** 2 + (k.y - b2) ** 2 
def astar(start_x,start_y,end_x,end_y):
    #记录路径长度
    move = [[0] * maxx for _ in range(maxx)]
    que = []
    start = Knight(start_x,start_y,0,heuristic(Knight(start_x,start_y,0,0),end_x,end_y))
    heapq.heappush(que,start)
    while que:
        cur = heapq.heappop(que)
        #终止条件,达到终点
        if cur.x == end_x and cur.y == end_y:
            return move[cur.x][cur.y]
        for dx,dy in direction:
            next_x = cur.x + dx 
            next_y = cur.y + dy 
            if 1 <= next_x < maxx and 1 <= next_y < maxx and move[next_x][next_y] == 0:
                move[next_x][next_y] = move[cur.x][cur.y] + 1 
                #走马日,1**2+2**2=5
                next_k = Knight(next_x,next_y,cur.g + 5,heuristic(Knight(next_x,next_y,0,0),end_x,end_y))
                heapq.heappush(que,next_k) 
    return -1
n = int(input())
for _ in range(n):
    a1,a2,b1,b2 = map(int,input().split())
    res = astar(a1,a2,b1,b2)
    print(res)

A算法搜的路径如何,完全取决于启发式函数怎么写,不能保证一定是最短路,设计启发式函数时要考虑时间效率和准确度之间的权衡。该算法的缺陷:A只从队列里取出距离终点最近的节点,大量不需要访问的节点都在队列里,会造成空间的过度消耗;有种常见是解决不了的,给出多个可能的目标,然后在多个可能目标中选择最近的节点,A*算法只擅长给出明确的目标然后找到最短路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值