python--蓝桥杯--最短路径

文章介绍了Dijkstra算法的基本概念,着重讲解了如何在遇到有多条最短路径的情况下,通过增加边权或点权来确定第二标尺最优路径。给出了代码示例,包括处理花费、物资收集等不同类型的第二标尺问题。
摘要由CSDN通过智能技术生成

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]

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值