1、Dijkstra算法
Dijkstra算法解决的是单源最短路径问题,即给定G(V,E)和起点s(起点又称为源点),求从起点s到达其它顶点的最短距离。(s为V0)
## 输入样例
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
## s为起点
def Dijkstra(s):
global d,vis,pre
## 起点到自己的距离为0
d[s]=0
## 循环n次
for i in range(n):
## u使d[u]最小
u=-1
MIN=float("inf")
## 找到未访问顶点中d[]最小的
for j in range(n):
if vis[j]==False and d[j]<MIN:
u=j
MIN=d[j]
## 找不到小于INF的d[u]说明,剩下的顶点与起点s不通
if u==-1:
return
## 标记u为已访问
vis[u]=True
for v in range(n):
## 如果v未访问,u能到达v,以u为中介点可以使d[v]更优
if vis[v]==False and G[u][v]!=float("inf") and d[u]+G[u][v]<d[v]:
## 优化
d[v]=d[u]+G[u][v]
pre[v]=u
## 顶点数、边数、起点编号
n,m,s=map(int,input().strip().split())
## 邻接矩阵
G=[[float("inf")]*n for _ in range(n)]
## 输入边及边权
for _ in range(m):
u,v,w=map(int,input().strip().split())
G[u][v]=w
## 起点到各点的最短路径
d=[float('inf')]*n
## 标记数组(标记访问过的位置)
vis=[False]*n
## 前驱结点pre[]
pre=[0]*n
Dijkstra(s)
for i in range(n):
print(d[i])
##输出样例
0
1
5
3
4
6
## 打印路径
## s是起点,v是当前访问编号
def DFS(s,v):
if v==s:
print(s,end=" ")
return
DFS(s,pre[v])
print(v,end=" ")
DFS(0,5)
## 输出样例
0 1 3 2 5
Dijkstra算法的基本用法大家应该已经掌握,但是题目肯定不会考的那么裸,更多时候会出现这样一种情况,即从起点到终点的最短路径不止一条。当碰到这种两条以上的最短路径,题目就会给出第二标尺(第一标尺是距离),要求在所有最短路径中选择第二标尺最优的一条路径。
第二标尺常见的是以下三种出题方法和组合:
1、给每条边再增加一个边权(比如说花费),求多条最短路径时,花费和最小
## 代码部分修改
## u-v的优化时
for v in range(n):
if vis[v]==False and G[u][v]!=float("inf"):
if d[u]+G[u][v]<d[v]:
d[v]=d[u]+G[u][v]
c[v]=c[u]+cost[u][n]
else:
## 更优
if d[u]+G[u][v]==d[v] and c[u]+cost[u][n]<c[v]:
c[v]=c[u]+cost[u][n]
2、给每个点增加一个点权(例如到达该城市能收集到的物资),求多条最短路径时,点权和最大
## 代码部分修改
## u-v的优化时
for v in range(n):
if vis[v]==False and G[u][v]!=float("inf"):
if d[u]+G[u][v]<d[v]:
d[v]=d[u]+G[u][v]
w[v]=w[u]+weight[u][n]
else:
## 更优
if d[u]+G[u][v]==d[v] and w[u]+weight[u][n]>w[v]:
w[v]=w[u]+weight[u][n]
## 输入样例
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1
def Dijkstra(s):
global d,vis,w,nums,pre
d[s]=0
w[s]=weight[s]
nums[s]=1
for i in range(n):
u=-1
MIN=float("inf")
for j in range(n):
if vis[j]==False and d[j]<MIN:
u=j
MIN=d[j]
if u==-1:
return
vis[u]=True
for v in range(n):
if vis[v]==False and G[u][v]!=float("inf") :
if d[u]+G[u][v]<d[v]:
d[v]=d[u]+G[u][v]
w[v]=w[u]+weight[v]
nums[v]=nums[u]
pre[v].clear()
pre[v].append(u)
else:
if d[u]+G[u][v]==d[v]:
## 更优
if w[u]+weight[v]>w[v]:
w[v]=w[u]+weight[v]
## 最短路径条数与点权无关,必须写在外面
nums[v]+=nums[u]
pre[v].append(u)
## 输入n m s e
n,m,s,e=map(int,input().strip().split())
##点权
weight=[-1]*n
##输入点权
weight=list(map(int,input().strip().split()))
##边权
G=[[float("inf")]*n for _ in range(n)]
##输入边权
for _ in range(m):
u,v,w=map(int,input().strip().split())
G[u][v]=w
##最短路径数
nums=[0]*n
##点权和
w=[0]*n
##最短距离
d=[float("inf")]*n
## 标记数组
vis=[False]*n
## 存放v的前一个结点u
pre=[[] for _ in range(n)]
Dijkstra(s)
##print(d)
##print(nums)
##print(w)
print(nums[e])
print(w[e]
## 输出样例
[0, 1, 2, 1, 2]
[1, 1, 2, 1, 1]
[1, 3, 4, 6, 9]
2
4
3、直接问有多少条最短路径
## 代码部分修改
## u-v的优化时
for v in range(n):
if vis[v]==False and G[u][v]!=float("inf"):
if d[u]+G[u][v]<d[v]:
d[v]=d[u]+G[u][v]
num[v]=num[u]
else:
## 更优
if d[u]+G[u][v]==d[v]:
num[v]+=num[u]