题目描述
一个快递公司希望在一条街道建立新的服务中心。公司统计了该街道中所有区域在地图上的位置,并希望能够以此为依据为新的服务中心选址:使服务中心到所有区域的距离的总和最小。
给你一个数组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
,使得所有区域到这个位置的距离之和最小。
解决思路:
- 问题分析:
- 对于每个区间
[left, right]
,如果服务中心的位置location
在区间左侧(即location < left
),那么距离为left - location
。 - 如果
location
在区间右侧(即location > right
),那么距离为location - right
。 - 如果
location
在区间内部(即left <= location <= right
),那么距离为0
。
- 对于每个区间
- 算法策略:
- 为了使得所有区域到这个位置的距离之和最小,我们可以选择某个区间的中点作为候选位置,然后计算所有区域到这个位置的距离之和,选取使得距离和最小的那个位置。
- 由于输入区间的左右端点值范围较大,我们可以通过中位数或类似的策略来缩小选择范围。
- 使用二分查找在所有区间中寻找最优的
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;
}
代码说明
- 函数
calculate_total_distance
: 计算给定location
时所有区域到该location
的总距离。 - 二分查找: 使用三分法在可能的
location
范围内查找,使得总距离最小的location
。 - 输入部分: 输入区域的数量
n
和每个区域的[left, right]
区间。 - 输出部分: 输出最优的
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
。