2024华为OD试题及答案-A074-服务中心选址

题目描述

一个快递公司希望在一条街道建立新的服务中心。公司统计了该街道中所有区域在地图上的位置,并希望能够以此为依据为新的服务中心选址:使服务中心到所有区域的距离的总和最小。

给你一个数组positions,其中positions[i] = [left, right] 表示第 i 个区域在街道上的位置,其中left代表区域的左侧的起点,right代表区域的右侧终点,假设服务中心的位置为location:

  • 如果第 i 个区域的右侧终点right满足 right < location,则第 i 个区域到服务中心的距离为 location - right;
  • 如果第 i 个区域的左侧起点left 满足 left > location,则第 i 个区域到服务中心的距离为left - location;
  • 如果第 i 个区域的两侧left,right满足left <= location <= right,则第 i 个区域到服务中心的距离为0

选择最佳的服务中心位置为location,请返回最佳的服务中心位置到所有区域的距离总和的最小值。

输入描述

先输入区域数组positions的长度n(1 ≤ n ≤ 10^5)

接下来 n 行每行输入成对的left和right值,以空格隔开

  • -10^9 <left ≤ 10^9
  • -10^9 <right ≤ 10^9

输出描述

输出为location

用例
输入3
1 2
3 4
10 20
输出8
说明
输入2
1 4
4 5
输出0
说明
输入4
5 6
1 8
7 15
2 4
输出3
说明
输入6
1 3
4 9
2 15
6 27
15 17
5 8
输出12
说明
输入16
41 67
0 34
24 69
58 78
62 64
5 45
27 81
61 91
42 95
27 36
4 91
2 53
82 92
16 21
18 95
26 47
输出127
说明

解析

题目要求在街道上找到一个位置,使得这个位置到所有区域的距离之和最小。每个区域用一个 [left, right] 的区间表示,要求找到一个最佳的 location,使得所有区域到这个位置的距离之和最小。

解决思路:

  1. 问题分析
    • 对于每个区间 [left, right],如果服务中心的位置 location 在区间左侧(即 location < left),那么距离为 left - location
    • 如果 location 在区间右侧(即 location > right),那么距离为 location - right
    • 如果 location 在区间内部(即 left <= location <= right),那么距离为 0
  2. 算法策略
    • 为了使得所有区域到这个位置的距离之和最小,我们可以选择某个区间的中点作为候选位置,然后计算所有区域到这个位置的距离之和,选取使得距离和最小的那个位置。
    • 由于输入区间的左右端点值范围较大,我们可以通过中位数或类似的策略来缩小选择范围。
    • 使用二分查找在所有区间中寻找最优的 location

C语言代码实现

以下是根据上述思路的C语言代码实现:

 
#include <stdio.h>
#include <stdlib.h>

#define ll long long

// 计算给定location时,所有区域到该location的总距离
ll calculate_total_distance(int location, int positions[][2], int n) {
    ll total_distance = 0;
    for (int i = 0; i < n; i++) {
        if (location < positions[i][0]) {
            total_distance += positions[i][0] - location;
        } else if (location > positions[i][1]) {
            total_distance += location - positions[i][1];
        }
    }
    return total_distance;
}

int main() {
    int n;
    scanf("%d", &n);
    int positions[n][2];
    
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &positions[i][0], &positions[i][1]);
    }
    
    // 二分查找
    int left = -1000000000;
    int right = 1000000000;
    
    while (left < right) {
        int mid1 = left + (right - left) / 3;
        int mid2 = right - (right - left) / 3;
        
        ll dist1 = calculate_total_distance(mid1, positions, n);
        ll dist2 = calculate_total_distance(mid2, positions, n);
        
        if (dist1 < dist2) {
            right = mid2 - 1;
        } else {
            left = mid1 + 1;
        }
    }
    
    printf("%d\n", left);
    
    return 0;
}

代码说明

  1. 函数 calculate_total_distance: 计算给定 location 时所有区域到该 location 的总距离。
  2. 二分查找: 使用三分法在可能的 location 范围内查找,使得总距离最小的 location
  3. 输入部分: 输入区域的数量 n 和每个区域的 [left, right] 区间。
  4. 输出部分: 输出最优的 location

Python 代码实现

将上述C语言代码转换成Python代码如下:

 
def calculate_total_distance(location, positions):
    total_distance = 0
    for left, right in positions:
        if location < left:
            total_distance += left - location
        elif location > right:
            total_distance += location - right
    return total_distance

def find_best_location(positions):
    left, right = -10**9, 10**9
    
    while left < right:
        mid1 = left + (right - left) // 3
        mid2 = right - (right - left) // 3
        
        dist1 = calculate_total_distance(mid1, positions)
        dist2 = calculate_total_distance(mid2, positions)
        
        if dist1 < dist2:
            right = mid2 - 1
        else:
            left = mid1 + 1
    
    return left

# 输入部分
n = int(input())
positions = [tuple(map(int, input().split())) for _ in range(n)]

# 找到最优的 location
best_location = find_best_location(positions)

# 输出结果
print(best_location)

代码说明

  • 函数 calculate_total_distance: 计算给定 location 时所有区域到该 location 的总距离。
  • 函数 find_best_location: 使用三分法查找最佳 location,使得总距离最小。
  • 输入部分: 接收 n 个区间 [left, right] 的输入。
  • 输出部分: 输出最优的 location

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值