在线机考|2024华为实习&秋招&春招编程题(最新)——第2题_公司班车上车点规划_200分(七)

题目内容

某公司基地搬迁到新地点之后,新规划了一条班车路线,在这条路线上会经过N个小区,计划在这些小区中挑选出M个作为上车点,小区的位置可以用一维坐标上的点来表示,小区到上车点的距离为两个坐标点差值的绝对值。现在给定N个小区的位置,即一维坐标上的整数点:x1、x2、…、xN $ ,我们希望所有小区到最近上车点的距离总和尽可能小,请计算这个最大值能够是多少?当该小区被作为上车点,该小区到上车点的距离为0。

输入描述

第一行有两个整数,用空格隔开:N M,1<M<=N<=100000

第二行有N个没有重复的递增的整数,用空格隔开,表示N个小区的位置,1<=xi<=1000000

输出描述

一个整数,表示所有小区到上车点距离的最大值的最小值

样例

输入:

5 2
1 2 3 6 7
输出:

1

说明:

将上车点设置在2、6这两个小区时,所有小区到上车点距离的最大值的最小值为1

解题思路

二分答案。二分这个最小可能值mid,如何check呢?我们贪心的考虑,我们放车站的时候尽可能大的覆盖到右边的区域,最多能覆盖positions[i]+mid这个位置,我们将下一个位置跳到upper_bound(positions.begin(), positions.end(), positions[i] + mid) - positions.begin()即可,最后检查车站数量是否不超过m即可

程序实现

C++

#include <bits/stdc++.h>
using namespace std;

// 函数用于判断在最大距离为mid时,是否可以用不超过M个上车点覆盖所有小区
bool canPlaceStations(const vector<int>& positions, int N, int M, int mid) {
    int count = 0; // 已放置的上车点数量
    int i = 0; // 当前检查的小区索引

    while (i < N) {
        count++; // 放置一个新的上车点
        // 找到最右边的一个小区,使得它不超过 positions[i] + mid
        int station_pos = positions[i] + mid;
        int j = upper_bound(positions.begin(), positions.end(), station_pos) - positions.begin();
        j--; // 上车点放置在 positions[j]

        // 现在,所有小区 <= positions[j] + mid 都被覆盖
        int cover_limit = positions[j] + mid;
        i = upper_bound(positions.begin(), positions.end(), cover_limit) - positions.begin();
    }

    return count <= M;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int N, M;
    cin >> N >> M;
    vector<int> positions(N);
    for(auto &x : positions) cin >> x;
    
    int left = 0;
    int right = positions[N-1] - positions[0];
    int answer = right;
    
    while(left <= right){
        int mid = left + (right - left) / 2;
        if(canPlaceStations(positions, N, M, mid)){
            answer = mid;
            right = mid - 1;
        }
        else{
            left = mid + 1;
        }
    }
    
    cout << answer;
}

Python

def can_place_stations(positions, N, M, mid):
    count = 0  # 已放置的上车点数量
    i = 0  # 当前检查的小区索引

    while i < N:
        count += 1  # 放置一个新的上车点
        station_pos = positions[i] + mid
        # 找到最右边的一个小区,使得它不超过 positions[i] + mid
        j = i
        while j < N and positions[j] <= station_pos:
            j += 1
        j -= 1  # 上车点放置在 positions[j]

        cover_limit = positions[j] + mid
        # 找到第一个超过 cover_limit 的小区
        while i < N and positions[i] <= cover_limit:
            i += 1

    return count <= M


def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    N, M = map(int, data[:2])
    positions = list(map(int, data[2:2 + N]))

    left = 0
    right = positions[-1] - positions[0]
    answer = right

    while left <= right:
        mid = (left + right) // 2
        if can_place_stations(positions, N, M, mid):
            answer = mid
            right = mid - 1
        else:
            left = mid + 1
    print(answer)


if __name__ == "__main__":
    main()

Java

import java.util.*;
import java.io.*;

public class Main {
    // 函数用于判断在最大距离为mid时,是否可以用不超过M个上车点覆盖所有小区
    public static boolean canPlaceStations(int[] positions, int N, int M, int mid){
        int count = 0; // 已放置的上车点数量
        int i = 0; // 当前检查的小区索引

        while (i < N){
            count++; // 放置一个新的上车点
            int station_pos = positions[i] + mid;
            // 找到最右边的一个小区,使得它不超过 positions[i] + mid
            int j = i;
            while (j < N && positions[j] <= station_pos){
                j++;
            }
            j--; // 上车点放置在 positions[j]
            
            // 现在,所有小区 <= positions[j] + mid 都被覆盖
            int cover_limit = positions[j] + mid;
            while (i < N && positions[i] <= cover_limit){
                i++;
            }
        }
        return count <= M;
    }

    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] first = br.readLine().split(" ");
        int N = Integer.parseInt(first[0]);
        int M = Integer.parseInt(first[1]);
        String[] posStr = br.readLine().split(" ");
        int[] positions = new int[N];
        for(int i=0;i<N;i++) positions[i] = Integer.parseInt(posStr[i]);
        
        int left =0;
        int right = positions[N-1] - positions[0];
        int answer = right;
        
        while(left <= right){
            int mid = left + (right - left)/2;
            if(canPlaceStations(positions, N, M, mid)){
                answer = mid;
                right = mid -1;
            }
            else{
                left = mid +1;
            }
        }
        System.out.println(answer);
    }
}