• 【阿良的算法之路】图论最短路算法模板


    图论总览🍉


    最短路问题无非是求一张地图中一个点a到另一个点b最短的路径,

            对于单源最短路,我们只需要求点1(第一个点)到其他所有点的最短路径;对于一个朴素的图(没有重边,也没有负环边的权重也不是负数)的情况下:我们使用堆优化的dirjkstra单源最短路径算法是最合适的。对于非朴素的图,我们需要使用Spfa单源最短路径算法

            对于多源最短路,我们求的确实每一个点到其他所有点的最短路径。多源最短路都不考虑朴素的图,也就是有重边,也有负环边的权重也是负数的情况,如果限制了最多只能经过k个点,那么我们使用Bellman-Ford多源最短路算法,不然使用Floya多源最短路算法。


    【模板】dirjkstra单源最短路径👑

    参考题目🍉

    题目描述🎈

    给定一个 n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。

    数据保证你能从 s 出发到任意点。

    输入格式🎈

    第一行为三个正整数 n, m, s。 第二行起 m 行,每行三个非负整数 u_i, v_i, w_i,表示从 u_i 到 v_i 有一条权值为 w_i 的有向边。

    输出格式🎈

    输出一行 n 个空格分隔的非负整数,表示 s 到每个点的距离。

    ————————————————

    1. '''
    2. # #AC Code(dirjkstra单源最短路径)# #
    3. '''
    4. import heapq
    5. from collections import defaultdict
    6. # 核心代码
    7. def dirjkstra():
    8. # 各节点到start的最短距离
    9. dirs = [float('inf')] * (n + 1)
    10. dirs[start] = 0
    11. # 已用节点,比set还快20% 所有没有释放False
    12. seen = [False] * (n + 1)
    13. pq = []
    14. heapq.heappush(pq, (0, start))
    15. # BFS
    16. while pq:
    17. # 获取
    18. _, u = heapq.heappop(pq)
    19. # 该节点是否用过
    20. if seen[u]:
    21. continue
    22. else:
    23. seen[u] = True
    24. # 找到邻接节点
    25. nodeList = graph[u]
    26. for v, w in nodeList:
    27. t = dirs[u] + w
    28. if t < dirs[v]:
    29. dirs[v] = t
    30. # 如果该邻接节点没有访问过才把该最短边加进去
    31. if not seen[v]:
    32. heapq.heappush(pq, (t, v))
    33. if dirs[-1] == float('inf'):
    34. return -1
    35. else:
    36. return dirs[-1]
    37. # 输入
    38. n, m = map(int, input().split())
    39. # 初始化
    40. start = 1
    41. # 建图
    42. graph = defaultdict(list)
    43. for _ in range(m):
    44. u, v, w = map(int, input().split())
    45. graph[u].append((v,w))
    46. answer = dirjkstra()
    47. print(answer)

    【模板】Spfa求最短路👑

    参考题目🍉

            给定一个n 个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。请你求出1号点到n 号点的最短距离,如果无法从1号点走到n号点,则输出impossible 。数据保证不存在负权回路。

    输入格式:🎈

            第一行包含整数n和m。接下来m行每行包含三个整数a, y,z,表示存在一条从点α到点g的有向边,边长为z。

    输出格式:🎈

            输出一个整数,表示1号点到n号点的最短距离。如果路径不存在,则输出impossible。

    数据范围:🎈

    1≤n, m≤10**5,

    图中涉及边长绝对值不超过10000。

    输入样例:🎈

    1. 3 3
    2. 1 2 5
    3. 2 3 -3
    4. 1 3 4

    输出样例:🎈

    2

    ————————————————

    1. '''
    2. # #AC Code(Spfa单源最短路 )# #
    3. NOTE:队列存储距离有更新的点。
    4. '''
    5. # 队列存储距离有更新的点
    6. def spfa():
    7. dirs = [float('inf')] * (n + 1) # 存储到1节点的最短距离
    8. dirs[1] = 0
    9. seen = [False] * (n + 1) # 该节点是否在队列中
    10. q = [1]
    11. while len(q):
    12. u = q.pop(0)
    13. seen[u] = False
    14. for v, w in g[u]:
    15. if dirs[u] + w < dirs[v]:
    16. dirs[v] = dirs[u] + w
    17. # 如果该邻接节点没有访问过才把该点加进去
    18. if not seen[v]:
    19. q.append(v)
    20. seen[v] = True
    21. if dirs[-1] == float('inf'):
    22. return 'impossible'
    23. else:
    24. return dirs[-1]
    25. # 建边
    26. n, m = map(int, input().split())
    27. g = {x: [] for x in range(1, n + 1)}
    28. for _ in range(m):
    29. a, b, w = map(int, input().split())
    30. g[a].append((b, w))
    31. ans = spfa()
    32. print(ans)

    【模板】Spfa判断负环👑

    参考题目🍉

    给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。

    请你判断图中是否存在负权回路。

    输入格式:🎈

    第一行包含整数n和m。

    接下来m行每行包含三个整数x, y, z, 表示存在一条从点x到点y的有向边,边长为z。

    输出格式:🎈

    如果图中存在负权回路,则输出Yes,否则输出No。

    数据范围:🎈

    输入样例:🎈

    1. 3 3
    2. 1 2 -1
    3. 2 3 4
    4. 3 1 -4

    输出样例:🎈

    Yes

    ————————————————

    1. '''
    2. # #AC Code(Spfa判断负环 )# #
    3. '''
    4. from collections import deque, defaultdict
    5. def spfa():
    6. dirs = [0] * (n + 1) # 表示的是1到s的最短距离
    7. seen = [False] * (n + 1) # 该节点是否走过
    8. cnt = [0] * (n + 1) # 表示的是当前最短路的边的数量
    9. q = deque([x for x in range(1, n + 1)])
    10. while len(q):
    11. u = q.popleft()
    12. seen[u] = False
    13. for v, w in g[u]:
    14. t = dirs[u] + w
    15. if t < dirs[v]:
    16. dirs[v] = t
    17. cnt[v] = cnt[u] + 1
    18. if cnt[v] >= n:
    19. return True
    20. if not seen[v]:
    21. q.append(v)
    22. seen[v] = True
    23. return False
    24. # 建图模板
    25. n, m = map(int, input().split())
    26. g = defaultdict(list)
    27. for _ in range(m):
    28. u, v, w = map(int, input().split())
    29. g[u].append((v, w))
    30. print("Yes" if spfa() else "No")

    【模板】Floya(不限制经过多少条边)👑

     ————————————————

    1. #### ####### #########################
    2. ### floyd多源最短路不限制经过多少条边 ###
    3. #### ####### ##########################
    4. def floyd():
    5. for k in range(1, n + 1):
    6. for i in range(1, n + 1):
    7. for j in range(1, n + 1):
    8. dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
    9. return
    10. n, m, k = map(int, input().split())#输入
    11. dp = [[float('inf')] * (n + 1) for _ in range(n + 1)]#开dp数组
    12. # d[i][j] 结点i到结点j的最短距离
    13. for i in range(1, n + 1): # 结点i到自己为0
    14. dp[i][i] = 0
    15. for _ in range(m): # m 条有向边
    16. u, v, w = map(int, input().split())
    17. dp[u][v] = min(dp[u][v], w) # 连边中u可能等于v此时选择最小的
    18. # 解决重边和自环 都选最小的
    19. floyd()
    20. for _ in range(k):
    21. u, v = map(int, input().split())
    22. print('impossible' if dp[u][v]==float('inf') else dp[u][v])

    【模板】Bellman-Ford多源最短路👑

    参考题目🍉

    给定一个 n 个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数

    请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible

    注意:图中可能 存在负权回路 。

    输入格式🎈

    第一行包含三个整数 n,m,k。

    接下来 mm 行,每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

    输出格式🎈

    输出一个整数,表示从 1 号点到 n 号点的最多经过 k 条边的最短距离。

    如果不存在满足条件的路径,则输出 impossible

    数据范围🎈

    1≤n,k≤5001≤n,k≤500,
    1≤m≤100001≤m≤10000,
    任意边长的绝对值不超过 1000010000。

    ————————————————

    1. '''
    2. # #AC Code(BF多源最短路)# #
    3. NOTE:从 1 号点到 n 号点的最多经过 k 条边的最短距离。
    4. # new_list = list !!当list的值改变了new_list也会随着改变
    5. # 正确做法: new_list = list(list)
    6. '''
    7. n, m, k = map(int, input().split())
    8. edgeList = [tuple(map(int, input().split())) for _ in range(m)]
    9. dirs = [float('inf') for _ in range(n + 1)]
    10. dirs[1] = 0
    11. for _ in range(k):
    12. back = list(dirs)
    13. for u, v, w in edgeList:
    14. dirs[v] = min(dirs[v], back[u] + w)
    15. if dirs[-1] == float('inf'):
    16. print('impossible')
    17. else:
    18. print(dirs[-1])

    【模板】Kruskal最小生成树(最短的一个环路)👑

    参考题目🍉

    给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。

    求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

    给定一张边带权的无向图=(V,E),其中V表示图中点的集合,E表示图中边的集合,n=|V\,m =|E。

    由V中的全部n个顶点和E中n―1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图的最小生成树。

    输入格式:🎈

    第一行包含两个整数n和m。

    接下来m行,每行包含三个整数u, v, ww,表示点u和点v之间存在一条权值为w的边。

    输出格式:🎈

    共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible 。

    数据范围:🎈


    输入样例:🎈

    1. 4 5
    2. 1 2 1
    3. 1 3 2
    4. 1 4 3
    5. 2 3 2 
    6. 3 4 4

    输出样例:🎈

    6
    1. '''
    2. # #AC Code(Kruskal最小生成树)# #
    3. NOTE:最短的一个环路。
    4. '''
    5. from collections import defaultdict, deque
    6. def find(x):
    7. if not p[x] == x:
    8. p[x] = find(p[x])
    9. return p[x]
    10. n, m = map(int, input().split())
    11. p = [_ for _ in range(n + 1)]
    12. g = []
    13. for _ in range(m):
    14. g.append(tuple(map(int, input().split())))
    15. g.sort(key=lambda x:x[2])
    16. cnt = 0
    17. res = 0
    18. for u, v, w in g:
    19. eu = find(u)
    20. ev = find(v)
    21. if eu == ev: continue
    22. p[ev] = eu
    23. res += w
    24. cnt += 1
    25. print('impossible') if not cnt == n - 1 else print(res)
  • 相关阅读:
    判断时间范围是否重叠(原理)
    第二章:Spring核心思想和IOC和AOP依赖注入
    习题练习 C语言(暑期第三弹)
    WRFV3.8.1编译报错,无法显示exe文件
    【算法题】100032. 使数组为空的最少操作次数
    【ES6 从入门到精通系列】学习笔记 23 篇(完结)
    java简单实现AIDL进程通信
    LRU和LFU算法的区别
    【数据结构】图的存储结构
    微信小程序授权登陆 getUserProfile
  • 原文地址:https://blog.csdn.net/qq_51831335/article/details/124996862