题解:洛谷 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

【核心思想】

  1. 问题分析:在二维平面上给定 \(n\) 个点,需要找到一个点(可以是任意实数坐标),使得所有点到该点的曼哈顿距离之和最小,并求满足该条件的不同位置的数量。由于曼哈顿距离在 \(x\)\(y\) 方向上是可分离的,总距离 \(D(P) = \sum |x_i - X| + \sum |y_i - Y|\),因此最小化问题可以分解为独立的一维问题:分别找到使 \(\sum |x_i - X|\) 最小的 \(X\) 区间,以及使 \(\sum |y_i - Y|\) 最小的 \(Y\) 区间,两个区间的笛卡尔积即为所有最优点的集合。

  2. 算法选择

    • 排序 + 中位数区间:在一维数轴上,使到所有点绝对距离之和最小的点,是所有中位数构成的区间。若点数为奇数,中位数唯一;若点数为偶数,则中位数区间为中间两个点之间的闭区间。因此,对 \(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\)
  3. 关键步骤

    • 读入数据:读取测试用例数 \(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
    • 输出答案cnt_x * cnt_y
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n)\),排序为瓶颈。
    • 空间复杂度:\(O(n)\),存储坐标数组。
  5. 贪心 + 中位数区间的核心思想

    • 曼哈顿距离的可分离性\(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
posted @ 2026-09-02 22:18  团爸讲算法  阅读(11)  评论(0)    收藏  举报