3973 无线网络(二分 + 双指针)

1. 问题描述:

农夫约翰的 n 头奶牛站在从牛棚到牧场的直线路径上,直线路径可看作一维数轴。因为他的奶牛喜欢保持电子邮件联系,所以约翰在这条直线路径上安装了 m 个 wifi 基站,以便所有的奶牛都被无线网络覆盖。所有基站都以相同功率工作。功率为 r 的基站,如果其所在位置为 x,则它可以将数据传输到 [x − r,x + r] 范围内的任何奶牛处。如果基站的功率为 0,则只会覆盖与其位于同一位置的奶牛。请你确定,在满足所有奶牛都被无线网络覆盖的前提下,基站的最小运行功率。

输入格式

第一行包含两个整数 n,m,表示奶牛的数量和基站的数量。第二行包含 n 个整数 a1,a2,…,an,表示每个奶牛的位置坐标。不同奶牛的坐标位置可能相同。所有奶牛的坐标 ai 是按非严格单调递增顺序给出的。第三行包含 m 个整数 b1,b2,…,bm,表示每个基站的位置坐标,不同基站的坐标位置可能相同。所有基站的坐标 bi 是按非严格单调递增顺序给出的。

输出格式

一个数,表示在满足所有奶牛都被无线网络覆盖的前提下,基站的最小运行功率。答案四舍五入到整数。

数据范围

前六个测试点满足,1 ≤ n,m ≤ 10。
所有测试点满足,1 ≤ n,m ≤ 10 ^ 5,−10 ^ 9 ≤ ai,bi ≤ 10 ^ 9。

输入样例1:

3 2
-2 2 4
-3 0

输出样例1:

4

输入样例2:

5 3
1 5 10 14 17
4 11 15

输出样例2:

3
来源:https://www.acwing.com/problem/content/description/3976/

2. 思路分析:

分析题目可以知道我们需要自定义一个r使得所有的奶牛可以被基站覆盖,一般遇到....求解"最小"或者是"最大"的问题首先判断能否使用二分解决;判断能否使用二分来解决需要看一下答案区间是否具有二段性,当枚举的答案为ans的时候,ans左边与右边是否一半满足条件另一半都不满足条件,如果ans左边的数值满足要求那么答案肯定是ans的左边而不是ans所以ans左边一定是不满足条件的,而对于ans右边的数值是一定可以覆盖所有的奶牛的,所以答案区间是有二段性的,也即能用二分来解决,二分的本质其实不是单调性而是二段性,有些问题不具有单调性,但是可以使用二分来解决的。可以发现二分枚举的左边界为0,右边界为ai最大值与最小值的差值,也即2e9,这样问题就转化为了如何快速判断当前枚举的mid是否满足条件呢?这里可以使用双指针来解决(定义yj <= xi中最大的一个指针j,当指针i向右走的时候指针j一定也是往右走的所以具有单调性也即可以使用双指针来解决),我们可以使用双指针找到距离ai左边最靠右的位置j,j + 1就是靠近ai的下一个位置,只需要判断这两个位置与ai的绝对值是否小于等于mid,如果发现其中一个不满足条件的时候直接返回False,说明当前mid不满足要求。

3. 代码如下:

from typing import List


class Solution:
    # 判断当前半径为mid的时候是否可以满足所有的基站覆盖所有的站点
    def check(self, mid: int, a: List[int], b: List[int]):
        n, m = len(a), len(b)
        j = 0
        for i in range(n):
            # 找到小于等于a[i]左边最靠右的位置, j + 1就是下一个位置, j与j+1就是靠近a[i]相邻的两个位置
            while j + 1 < m and b[j + 1] <= a[i]: j += 1
            if abs(a[i] - b[j]) > mid:
                if j + 1 >= m or abs(a[i] - b[j + 1]) > mid:
                    return False
        return True

    # 一开始的时候感觉像是二分
    def process(self):
        n, m = map(int, input().split())
        a = list(map(int, input().split()))
        b = list(map(int, input().split()))
        l, r = 0, 2 * 10 ** 9
        while l < r:
            mid = l + r >> 1
            if self.check(mid, a, b):
                r = mid
            else:
                l = mid + 1
        return r


if __name__ == '__main__':
    print(Solution().process())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值