第十四届蓝桥杯省赛(Python)——管道问题

一、问题描述

二、算法思想

本题我们可以将问题的解划分成一个范围最好的情况下是从管道最短情况下,第一时刻开始开放第一个闸门,则每一个传感器最早均检测到水流的时间为1,最坏情况下是管道最长的情况,从最后一个时刻开始开放最后一个闸门,则每一个传感器最早均检测到水流的时间为等待闸门开启时间(10^9)+水流贯穿整个通道时间(也就为管道长度10^9)=2*10^9,所以问题的解的规模在1~2*10^9,所以我们一定可以在整个解中根据管道开放的时间去寻找到一个最佳解,如下图所示,我们可以联想到用二分法去查找中位值,如果早于这个时间,肯定是不能贯穿整个水管,因为时间越久,阀门检测水流的范围越广,因此解一定在中位值的右边。

其次,我们在使用二分查找最优值时,如何设置判断条件去划分下一个子区间,这个条件为检查该mid值下是否水流全覆盖水管,然后不断划分子区间,直至二分法只剩下一个或两个元素时结束。而这个检查函数check()中,根据题目所给的阀门在该时刻下检测范围可以生成一系列检测区间,将其升序排序,就转变成了区间合并的问题,会遇到以下三种没有全部覆盖的情况,其他均为全覆盖的情况。

三、代码描述(附注释)

n,ll=map(int,input().split())
L=[]
for i in range(n):
    L.append(list(map(int,input().split())))
l1=sorted(L,key=lambda x:x[1])  #按照阀门开启时间排个序,减少运行时间

l,r=1,2*10**9+1  #确定最好、最坏情况的范围

#检查函数(检查是否覆盖了所有水管)
def check(mid):
    res=[] #检测范围区间
    for i in l1:
        if i[1]>mid: continue  #阀门未到开启时间
        else:
            l=max(1,i[0]-(mid-i[1])) #左范围
            r=min(ll,i[0]+(mid-i[1]))  #右范围
            res.append([l,r]) #记录检测区间
    # print(res)
    res.sort() #默认按照第一个值降序排序
    #区间合并
    if res[0][0]>1: return False  #1 第一个位置不能被检测
    rr=res[0][1]
    for j in range(1,len(res)):
        if res[j][0]>rr and rr+1!=res[j][0]:  return False  #2 中间某个位置不能被检测
        else: rr=max(rr,res[j][1]) #更新检测范围
    if rr<ll: return False #3 最后一个位置不能被检测
    return True #全覆盖

#二分查找
while l+1!=r:
    mid=(l+r)//2
    if check(mid): #中位值在左边
        r=mid
    else: l=mid  #中位值在右边
print(r)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值