2025B-基站维护工程师-200分

刷题笔记合集🔗

问题描述

小基是一名基站维护工程师,负责管理一片区域内的基站。这片区域可以看作是一个二维平面,每个基站都有一个坐标 和一个信号覆盖半径 。一个基站可以覆盖到所有与其距离不超过 的点。

现在,小基需要检修一些基站。由于检修资源有限,他希望选择尽可能少的基站进行检修,同时确保所有指定的服务点都能被这些检修后的基站覆盖到。

请你帮助小基计算最少需要检修多少个基站。

输入格式

第一行包含两个整数 ,分别表示基站的数量和服务点的数量。

接下来的 行,每行包含三个整数 ,表示第 个基站的坐标 和信号覆盖半径

接下来的 行,每行包含两个整数 ,表示第 个服务点的坐标

输出格式

输出一个整数,表示最少需要检修的基站数量。如果无法覆盖所有服务点,则输出

样例输入1

3 3
0 0 5
10 0 5
5 5 5
1 1
8 1
5 6

样例输出1

2

样例输入2

2 3
0 0 5
10 0 5
1 1
8 1
20 20

样例输出2

-1

样例输入3

4 5
0 0 5
10 0 5
5 5 5
15 5 5
1 1
8 1
5 6
12 3
16 6

样例输出3

3

样例解释

样例 解释说明
样例1 有3个基站和3个服务点。基站1可以覆盖服务点1,基站2可以覆盖服务点2,基站3可以覆盖服务点3。需要检修基站1和基站2才能覆盖所有服务点,所以最少需要检修2个基站。
样例2 有2个基站和3个服务点。基站1可以覆盖服务点1,基站2可以覆盖服务点2,但没有基站可以覆盖服务点3,所以无法覆盖所有服务点,输出-1。
样例3 有4个基站和5个服务点。需要检修基站1、基站3和基站4才能覆盖所有服务点,所以最少需要检修3个基站。

数据范围

题解

这道题目本质上是一个集合覆盖问题。需要选择最少数量的基站,使得所有服务点都被覆盖。

首先,需要确定每个基站可以覆盖哪些服务点。对于基站 和服务点 ,如果它们之间的欧几里得距离不超过基站的覆盖半径 ,即 ,那么这个基站可以覆盖这个服务点。

接下来,可以使用贪心算法来解决这个问题:

  1. 对于每个基站,计算它可以覆盖的服务点集合。
  2. 每次选择能覆盖最多未覆盖服务点的基站。
  3. 重复步骤2,直到所有服务点都被覆盖,或者没有基站可以覆盖更多的服务点。

这个贪心策略虽然不一定能得到最优解,但在实际问题中通常表现良好。对于本题的数据范围,这种方法是可行的。

时间复杂度分析:

  • 计算每个基站可以覆盖的服务点需要 的时间。
  • 贪心选择基站的过程最多需要 的时间。
  • 因此,总时间复杂度为

对于给定的数据范围 (),这个复杂度是可以接受的。

参考代码

import math

def get_len(p1, p2):
    """
    计算两点之间的欧几里得距离
    
    参数:
        p1: 第一个点的坐标 (x, y)
        p2: 第二个点的坐标 (a, b)
    
    返回:
        两点之间的距离
    """
    return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)

def solve_prob():
    """
    找出最少需要检修的基站数量
    
    返回:
        最少需要检修的基站数量,如果无法覆盖所有服务点则返回-1
    """
    # 读取基站数量和服务点数量
    n_bs, n_sp = map(int, input().split())
    
    # 读取基站信息
    bs_data = []
    for _ in range(n_bs):
        x, y, r = map(int, input().split())
        bs_data.append((x, y, r))
    
    # 读取服务点信息
    sp_data = []
    for _ in range(n_sp):
        a, b = map(int, input().split())
        sp_data.append((a, b))
    
    # 计算每个基站可以覆盖的服务点
    cov_map = [[] for _ in range(n_bs)]
    
    # 遍历所有基站
    for i in range(n_bs):
        x, y, r = bs_data[i]
        # 遍历所有服务点
        for j in range(n_sp):
            a, b = sp_data[j]
            # 如果服务点在基站覆盖范围内,则添加到覆盖列表
            if get_len((x, y), (a, b)) <= r:
                cov_map[i].append(j)
    
    # 使用贪心算法选择基站
    cnt = 0
    cov = set()
    
    # 当还有未覆盖的服务点时继续选择基站
    while len(cov) < n_sp:
        best = -1
        best_add = set()
        
        # 找出能覆盖最多未覆盖服务点的基站
        for i in range(n_bs):
            # 计算当前基站可以新覆盖的服务点
            new_add = set(cov_map[i]) - cov
            if len(new_add) > len(best_add):
                best = i
                best_add = new_add
        
        # 如果没有基站可以覆盖更多的服务点,则无法覆盖所有服务点
        if best == -1:
            return -1
        
        # 选择当前最优的基站
        cnt += 1
        cov |= best_add
    
    return cnt

# 主函数
if __name__ == "__main__":
    print(solve_prob())
#include <iostream>
#include <vector>
#include <cmath>
#include <unordered_set>
using namespace std;

/**
 * 计算两点之间的欧几里得距离
 * 
 * @param x1 第一个点的x坐标
 * @param y1 第一个点的y坐标
 * @param x2 第二个点的x坐标
 * @param y2 第二个点的y坐标
 * @return 两点之间的距离
 */
double dist(int x1, int y1, int x2, int y2) {
    return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}

/**
 * 检查是否可以覆盖所有服务点
 * 
 * @param n 基站数量
 * @param m 服务点数量
 * @para

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论

相关推荐

不愿透露姓名的神秘牛友
昨天 12:18
点赞 评论 收藏
分享
05-20 13:59
门头沟学院 Java
米黑子米黑子:你这个成绩不争取下保研?
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务