图论2图的应用补充

图论1基础内容-CSDN博客

图的应用

4.1 拓扑排序

拓扑排序针对有向无环图的顶点进行线性排列的算法,使得对于任何来自顶点A指向顶点B的边,A都在序列中出现在B之前。这样的排序存在于有向无环图中,而对于非有向无环图则不存在拓扑排序。

拓扑排序也可以用来检测图中有无成环

4.2 最小生成树

生成树是连通图的极小连通子图,多一条边就会成环,少一条边即无法构成连通图

生成树的代价:

G=(V,E)是一个无向连通图,代价是生成树上各边的边权和

生成树代价=9+49+11+1+21=91

最小生成树即是代价最小的生成树

上图中代价min=1+7+10+7+5=30

最小生成树解析

4.2.1 Kruskal(加边)

将边从小到大排序

利用并查集 合并边

如果该边的加入不会成换,则加入,否则不加入

时间复杂度分析:边排序时间+并查集时间

蓝桥账户中心

蓝桥889

复制代码
# n 个交叉路口 -- n个点 m条边 无向图`
`# 最小生成树`
`# 1≤n≤300,1≤m≤1e5  边>>点 稠密图 最好用Prmie`
`# Kruskal版`
`n,m =` `map(int,input().split())`
`# 存图`
`e =` `[]`
`# m条边 连边`
`for i in` `range(m):`
`  u,v,c =` `map(int,input().split())`
`  e.append((c,u,v))` `# 把分值c放第一位,方便后续排序`
`# 边排序`
`e.sort()`
`# 把所有的交叉路口直接或间接的连通起来 -- 并查集`
`p =` `list(range(n+1))`
`# 递归找根`
`def` `find_root(x):`
  `if x != p[x]:`
`    p[x]` `= find_root(p[x])`
  `return p[x]`
`# 从小到大遍历所有边,进行合并 找最小的生成树`
`# sum记录边权和,max_val记录最大的边权`
`sum, max_val =` `0,0`
`for w,u,v in e:`
`  rootu = find_root(u)`
`  rootv = find_root(v)`
  `if rootv != rootu:`
`    p[rootv]` `= rootu`
    `# 合并次数+1 修路的条数+1`
    `sum` `+=` `1`
`    max_val =` `max(max_val,w)`
`print(sum,max_val)`
`
4.2.2 Prime(加点)

算法流程:d[i]表示点i和集合的距离

选择一个初始点(随意)u加入集合S,d[u]=0

利用点u更新其它的点(加入离当前集合最近的点)

在d中选择最小未加入集合的点作为新一轮的u

重复上述至所有点加入集合(过程中有两个分区,一个是加入集合的点,另一个是还未加入的点)

复制代码
# 蓝桥889`
`# n 个交叉路口 -- n个点 m条边 无向图`
`# 最小生成树`
`# 1≤n≤300,1≤m≤1e5  边>>点 稠密图 最好用Prmie`
`# Prime版`
`import math`
`n,m = map(int,input().split())`
`INF = math.inf`
`# 存图`
`mapp = [[INF]*(n+1) for _ in range(n+1)]`
`for _ in range(m):`
`  u,v,w = map(int,input().split())`
`  mapp[u][v] = mapp[v][u] = min(mapp[u][v],w)`
`# 定义集合d`
`d = [INF] * (n+1)`
`max_val = 0`
`# 初始化d[1]=0`
`u = 1`
`# 跑Prime加点`
`for i in range(n-1): # 除去第一个点,还有n-1个点`
`  d[u] = 0`
`  # 初始化下一个点,下一条边`
`  next_u = 0`
`  next_val = INF`
`  for v in range(1,n+1):`
`    if d[v] == 0: continue # 该点不与当前集合d连通`
`    d[v] = min(d[v], mapp[u][v]) # mapp[u][v]点u到v的边权`
`    # 第i次加点时找到离当前集合更近的点`
`    if d[v] < next_val:`
`      next_val = d[v]`
`      next_u = v`
`  # 基于上一轮扩大下一轮集合,更新d`
`  u = next_u`
`  max_val = max(next_val, max_val)`
`print(n-1, max_val)`
`
4.3 最短路问题

最短路径是两个顶点之间经历的边上边权之和最小的可达路径

4.3.1 Floyed

用于处理多源最短路,从多个点出发到一个点的最短路,可以存在负权边。

蓝桥账户中心

蓝桥8336

复制代码
# n点m边`
`# floyd 利用动态规划 三层循环`
`# 定义dp[k][i][j]表示点i到点j的路径(除去起点和终点)中编号最大不超过k的情况下,i到j的最短距离`
`# 当加入 第k个点 作为i到j的 中间点`
`# dp[k][i][j] = mian(dp[k-1][i][j], dp[k-1][i][k]+dp[k-1][k][j])`
`import math`
`n,m =` `map(int,input().split())`
`# 城市i的商品产量`
`a =` `[0]` `*` `(n+1)`
`# 城市i的商品生产成本`
`p =` `[0]` `*` `(n+1)`
`# 城市i的商品售卖单价`
`s =` `[0]` `*` `(n+1)`
`INF = math.inf`
`# 一件商品从城市i运往城市j的利润:gi,j=sj-pi-fij`
`# 其中fi,j是路径费用`
`f =` `[[INF]` `*(n+1)` `for _ in` `range(n+1)]` `# fij为INF表示不通路`
`g =` `[[0]` `*(n+1)` `for _ in` `range(n+1)]` 
`# 输入a,p,s`
`for i in` `range(1,n+1):`
`  a[i],p[i],s[i]` `=` `map(int,input().split())`
`# 输入图`
`for i in` `range(1,m+1):`
`  u,v,w =` `map(int,input().split())`
`  f[u][v]` `= f[v][u]` `=` `min(f[u][v],w)`
`# 对角线费用为0 n个点 `
`for i in` `range(1,n+1):`
`  f[i][i]` `=` `0` 
`# floyd 动态规划 三层循环 跑一遍多源全图最短路填f路费表`
`for k in` `range(1,n+1):`
  `for i in` `range(1,n+1):`
    `for j in` `range(1,n+1):`
`      f[i][j]` `=` `min(f[i][j], f[i][k]` `+ f[k][j])`
`# 填完路费 现在算利润 填g 把i城市生产的产品送到城市j卖`
`for i in` `range(1,n+1):`
  `for j in` `range(1,n+1):`
`    g[i][j]` `= s[j]` `- p[i]` `- f[i][j]`
`# 求全图的最大利润`
`max_g =` `0`
`for i in` `range(1,n+1):`
  `# 在第二层循环中作一个判断是否有交易的依据`
`  max_s =` `-1`
  `for j in` `range(1,n+1):`
`    max_s =` `max(max_s,g[i][j])`
`  max_g +=` `max(0, max_s)` `* a[i]` `# 乘上产品数量`
`print(max_g)` 
`
4.3.2 Dijkstra

用于处理单源最短路,从一个点出发到一个点的最短路,不可以存在负权边。

复制代码
# n点m边 有向图`
`# 从皇宫到每个建筑的最短路径是多少 -- 单源最短路`
`from queue import PriorityQueue`
`import math`
`INF = math.inf`
`# dijkstra ,s:起点`
`def` `dijkstra(s):`
  `# 求从起点s出发到各个点i的最短路径`
  `# d[i]表示从起点s出发到点i的最短的最短路径`
`  d =` `[INF]*(n+1)`
  `# vis[i]表示第i个点是否出队列`
`  vis =` `[0]*(n+1)`
  `# 创建优先队列`
`  q = PriorityQueue()`
  `# 起点初始化距离0`
`  d[s]` `=` `0`
  `# 起点入队列`
`  q.put((d[s],s))`
  `# 当队列非空`
  `while q.queue:`
`    dis,u = q.get()`
    `# 每个点只有第一次出队列有效`
    `if vis[u]:continue`
`    vis[u]` `=` `1`
    `# 松弛 找离当前点在连通状态下的最近点`
    `for v,w in G[u]:`
      `if d[v]` `> d[u]` `+ w:`
`        d[v]` `= d[u]` `+ w`
`        q.put((d[v],v))`
  `# 处理完成d数组后按题目要求不通的距离为视为-1      `
  `for i in` `range(n+1):`
    `if d[i]` `== INF:`
`      d[i]` `=` `-1`
  `print(*d[1:],sep=' ')`


`n,m =` `map(int,input().split())`
`# 存图`
`G =` `[[]` `for i in` `range(n+1)]`
`for _ in` `range(m):`
`  u,v,w =` `map(int,input().split())`
`  G[u].append([v,w])`
`dijkstra(1)`
`
相关推荐
九圣残炎4 分钟前
【从零开始的LeetCode-算法】3227. 字符串元音游戏
java·算法·leetcode
KevinAha7 分钟前
django 实战(python 3.x/django 3/sqlite)
python·django·sqlite
梁小憨憨30 分钟前
变分推断(Variational Inference)
人工智能·算法·机器学习
就爱学编程38 分钟前
重生之我在异世界学编程之C语言:选择结构与循环结构篇
c语言·数据结构·算法
是十一月末39 分钟前
Python语法之正则表达式详解以及re模块中的常用函数
开发语言·python·正则表达式
一只大侠43 分钟前
输入一串字符,以“?”结束。统计其中字母个数,数字个数,其它符号个数。:JAVA
java·开发语言·算法
嗨信奥1 小时前
2023年第十四届蓝桥杯Scratch国赛真题—推箱子
青少年编程·蓝桥杯
winstongit1 小时前
捷联惯导原理和算法预备知识
算法·机器人
灵封~1 小时前
PythonQt练习
python
想成为高手4992 小时前
深入理解AVL树:结构、旋转及C++实现
开发语言·数据结构·c++