题解:学而思编程 货仓选址
【题目来源】
学而思编程:货仓选址
【题目描述】
在一条数轴上有 \(n\) 家商店,它们的坐标分别为 \(a_1\) 到 \(a_n\)
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
【输入】
第一行输入整数 \(n\)。
第二行 \(n\) 个整数 \(a_1\) 到 \(a_n\)
【输出】
输出一个整数,表示距离之和的最小值。
【输入样例】
4
6 2 9 1
【输出样例】
12
【核心思想】
-
问题分析:给定 \(n\) 个商店在数轴上的坐标 \(a_1, a_2, \ldots, a_n\),需要选择一个位置建立货仓,使得货仓到所有商店的距离之和最小。这是一个经典的中位数贪心问题,关键在于最优位置是中位数。
-
算法选择:
- 中位数性质:对于一维数轴上的点,使得到所有点距离之和最小的位置是中位数
- 数学证明:设选址位置为 \(x\),总距离为 \(f(x) = \sum_{i=1}^{n} |a_i - x|\)。当 \(x\) 为中位数时,\(f(x)\) 取得最小值
- 配对优化:排序后,最大与最小配对、次大与次小配对,每对的差值之和即为答案
-
关键步骤:
- 读取输入:\(n\)(商店数量)、\(a[1..n]\)(商店坐标)
- 排序:
sort(a + 1, a + n + 1)从小到大排序 - 配对计算(遍历 \(i\) 从 \(1\) 到 \((n+1)/2\)):
- 配对差值:
ans += a[n-i+1] - a[i](最大与最小配对)
- 配对差值:
- 输出结果:最小距离之和 \(ans\)
-
时间/空间复杂度:
- 时间复杂度:\(O(n \log n)\),主要是排序复杂度
- 空间复杂度:\(O(n)\),存储商店坐标
-
中位数贪心的核心思想:
- 中位数最优性:在一维情况下,中位数是使得到所有点距离之和最小的位置
- 排序配对技巧:排序后首尾配对,利用对称性简化计算
- 贪心正确性:中位数将数轴分成两部分,左右两侧的点数平衡,总距离最小
- 数学推导:通过绝对值函数的性质可以严格证明中位数的最优性
- 适用于一维选址问题、距离最小化、带权中位数等问题
【算法标签】
贪心
【代码详解】
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long n, a[100005], ans; // ans: 最终结果
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a + 1, a + n + 1); // 从小到大排序
// 计算最大元素与最小元素的差值之和
for (int i = 1; i <= (n + 1) / 2; i++)
{
ans += a[n - i + 1] - a[i]; // 最大与最小配对
}
cout << ans;
return 0;
}
【运行结果】
4
6 2 9 1
12
浙公网安备 33010602011771号