题解:洛谷 CF1486B Eastern Exhibition
【题目来源】
洛谷:CF1486B Eastern Exhibition - 洛谷
【题目描述】
二维平面上有 \(n\) 个点,要找一个点,使得所有点到它的曼哈顿距离( \(x\) 和 \(y\) 的坐标差距之和)之和最小。请问有几个满足该要求的点?
【输入】
First line contains a single integer \(t(1 \leq t \leq 1000)\) — the number of test cases.
The first line of each test case contains a single integer \(n(1 \leq n \leq 1000)\) . Next n lines describe the positions of the houses \((x_i, y_i)\) \((0 \leq x_i, y_i \leq 10^9)\).
It's guaranteed that the sum of all n does not exceed \(1000\).
【输出】
For each test case output a single integer - the number of different positions for the exhibition. The exhibition can be built in the same point as some house.
【输入样例】
6
3
0 0
2 0
1 2
4
1 0
0 2
2 3
3 1
4
0 0
0 1
1 0
1 1
2
0 0
1 1
2
0 0
2 0
2
0 0
0 0
【输出样例】
1
4
4
4
3
1
【核心思想】
-
问题分析:在二维平面上给定 \(n\) 个点,需要找到一个点(可以是任意实数坐标),使得所有点到该点的曼哈顿距离之和最小,并求满足该条件的不同位置的数量。由于曼哈顿距离在 \(x\) 和 \(y\) 方向上是可分离的,总距离 \(D(P) = \sum |x_i - X| + \sum |y_i - Y|\),因此最小化问题可以分解为独立的一维问题:分别找到使 \(\sum |x_i - X|\) 最小的 \(X\) 区间,以及使 \(\sum |y_i - Y|\) 最小的 \(Y\) 区间,两个区间的笛卡尔积即为所有最优点的集合。
-
算法选择:
- 排序 + 中位数区间:在一维数轴上,使到所有点绝对距离之和最小的点,是所有中位数构成的区间。若点数为奇数,中位数唯一;若点数为偶数,则中位数区间为中间两个点之间的闭区间。因此,对 \(x\) 坐标排序后,最优 \(X\) 的范围为 \([x_{(n-1)/2}, x_{n/2}]\)(下标从 \(0\) 开始),该区间内的整数点个数为 \(x_{n/2} - x_{(n-1)/2} + 1\)。同理可得 \(Y\) 的可行范围大小。最终答案即为两个区间大小的乘积。
- 复杂度:排序 \(O(n \log n)\),每个测试用例独立处理,总 \(n\) 不超过 \(1000\)。
-
关键步骤:
- 读入数据:读取测试用例数 \(t\),对每个用例读取 \(n\) 和 \(n\) 个点的坐标 \((x_i, y_i)\)。
- 分别排序:将所有 \(x_i\) 存入数组 \(a\),所有 \(y_i\) 存入数组 \(b\),分别升序排序。
- 计算区间大小:
- \(x\) 方向可行位置数:
cnt_x = a[n/2] - a[(n-1)/2] + 1。 - \(y\) 方向可行位置数:
cnt_y = b[n/2] - b[(n-1)/2] + 1。
- \(x\) 方向可行位置数:
- 输出答案:
cnt_x * cnt_y。
-
时间/空间复杂度:
- 时间复杂度:\(O(n \log n)\),排序为瓶颈。
- 空间复杂度:\(O(n)\),存储坐标数组。
-
贪心 + 中位数区间的核心思想:
- 曼哈顿距离的可分离性:\(L_1\) 距离在 \(x\) 和 \(y\) 方向上独立,因此二维问题可分解为两个独立的一维中位数问题。
- 一维中位数区间:在数轴上,使绝对距离和最小的点集合是中位数区间。当 \(n\) 为奇数时,区间缩为一个点;当 \(n\) 为偶数时,区间为中间两个数之间的所有点(包括端点)。
- 最优点的计数:两个方向上的最优区间相互独立,因此总最优位置数为两个区间长度的乘积。
- 适用场景:适用于曼哈顿距离下的中心选址问题,核心是利用坐标分离性将二维降为一维。
【算法标签】
普及 #贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 使用长整型
const int MAX_N = 1005; // 定义数组最大长度
int t, n; // t: 测试用例数, n: 每个用例的点数
int a[MAX_N], b[MAX_N]; // a: 存储x坐标, b: 存储y坐标
signed main()
{
// 输入测试用例数
cin >> t;
// 处理每个测试用例
while (t--)
{
// 初始化数组
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
// 输入点数
cin >> n;
// 输入所有点的坐标
for (int i = 0; i < n; i++)
cin >> a[i] >> b[i];
// 对x坐标和y坐标分别排序
sort(a, a + n);
sort(b, b + n);
// 计算x方向的可行范围
int x = a[n / 2] - a[(n - 1) / 2] + 1;
// 计算y方向的可行范围
int y = b[n / 2] - b[(n - 1) / 2] + 1;
// 输出可行解的个数(x范围 × y范围)
cout << x * y << endl;
}
return 0;
}
【运行结果】
6
3
0 0
2 0
1 2
1
4
1 0
0 2
2 3
3 1
4
4
0 0
0 1
1 0
1 1
4
2
0 0
1 1
4
2
0 0
2 0
3
2
0 0
0 0
1
浙公网安备 33010602011771号