Acwing:通信线路(二分+双端队列bfs Python)

题目链接🔗:340. 通信线路 - AcWing题库

分析:

思路如下:

因为题目要求的是:从1到N的路线上,第K+1长的路最小,所以我们可以二分枚举边权,看是否有小于等于K条路的边权大于它。

对于每个枚举的答案,做一次双端队列的bfs,节点1作为起点,返回一个布尔值:走到N的最短路中,是否有小于等于K条路的边权是大于被枚举的边权的

若返回True,说明有小于等于K条路的边权是大于被枚举的边权,所以right=mid,即继续往下枚举边权,反之则像大枚举边权。

更多细节请看注释~

import collections
INF = float('inf')
N,P,K = map(int,input().split())
Map = [[0 for i in range(N+1)]for j in range(N+1)]

for i in range(P) :
    a,b,c = map(int,input().split())
    Map[a][b] = Map[b][a] = c # 无向图存边
    
def check(bound) :
    flag = [1 for i in range(N+1)] # 判断当前点是否被用过
    dis = [INF for i in range(N+1)] # 当前点到起点的最短距离
    dis[1] = 0 # 起点到起点的距离为0
    queue = collections.deque() # 双端队列存储当前点
    queue.append(1)
    while queue : 
        node = queue.popleft()
        if not flag[node] : continue # 这里需要注意 :一定要在出队列时判重,而不是入队列的时候,否则答案可能不正确
        flag[node] = 0 # 这个点已经被用过了
        for i in range(1,N+1) :
            if Map[node][i] : # 如果有边
                tmp = Map[node][i] > bound # 关键点:如果当前边权是大于bound(二分值)的,我们把这个边权设为1,反正为0
                if dis[i] > dis[node] + tmp : # 如果可以更新答案
                    dis[i] = dis[node] + tmp
                    if tmp : queue.append(i) # 如果tmp==1 : 将这个点放入队尾,反之放入队头
                    else : queue.appendleft(i)
    return dis[N] <= K # 返回是否有小于等于K条路的边权是大于被枚举的边权
                

left,right = 0,10**6+1 # 二分的端点,不取10**6作为右端点,是因为如果结果输出为10**6,不能判断是无解还是答案确实为10**6
while left < right :
    mid = (left+right)>>1 # 二分
    if check(mid) : right = mid 
    else : left = mid + 1
if right == 10**6 + 1 : right = -1 # 判断是否无解
print(right)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UCSD.KS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值