1 条题解

  • 0
    @ 2025-4-8 20:22:13

    以下是本题的解题思路:

    问题理解

    本题要解决的是为蜜蜂制定一个调度表,让蜜蜂去访问草地上的所有花朵。调度表由若干组花朵组成,每只蜜蜂负责一组。一组花朵序列的权重是该序列中相邻两朵花距离的最大值,一组花朵的权重是所有可能序列中权重的最小值,而调度表的权重是所有组中权重的最大值。我们的目标是找到使调度表权重最小的方案。

    核心思路

    使用二分查找结合并查集来解决这个问题。二分查找用于确定可能的最小权重值,而并查集用于判断在给定的最大距离下,能否将花朵分成不超过 BB 组。

    具体步骤

    1. 数据输入与存储

    • 读取输入的花朵数量 FF 和蜜蜂数量 BB
    • 接着读取每朵花的坐标 (X,Y)(X, Y),并将这些坐标存储在一个结构体数组中,方便后续处理。

    2. 计算两点间距离

    • 定义一个函数来计算任意两朵花之间的欧几里得距离,公式为 d=(x1x2)2+(y1y2)2d = \sqrt{(x_1 - x_2)^2+(y_1 - y_2)^2},其中 (x1,y1)(x_1, y_1)(x2,y2)(x_2, y_2) 分别是两朵花的坐标。

    3. 并查集的使用

    • 并查集是一种用于处理不相交集合的合并与查询问题的数据结构。在本题中,我们使用并查集来判断哪些花朵可以被划分到同一组。
    • 初始化并查集,每个花朵的父节点初始为自身。
    • 遍历所有花朵对,如果两朵花之间的距离小于等于当前二分查找的中间值(即当前尝试的最大距离),则将这两朵花所在的集合合并。

    4. 二分查找

    • 二分查找的范围是从 00 到一个足够大的值(如 1e91e9)。
    • 在每次二分查找中,取中间值 midmid 作为当前尝试的最大距离。
    • 调用检查函数 check,判断在这个最大距离下,能否将花朵分成不超过 BB 组。
      • 如果可以,说明这个最大距离可能偏大,将右边界更新为 midmid
      • 如果不可以,说明这个最大距离偏小,将左边界更新为 midmid
    • 不断重复上述步骤,直到左右边界的差值小于一个很小的阈值(如 1e61e - 6),此时的右边界即为最小的最大距离。

    5. 输出结果

    • 将最终得到的最小最大距离四舍五入到两位小数并输出。

    复杂度分析

    • 时间复杂度:二分查找的时间复杂度为 O(log(1e9))O(\log(1e9)),每次检查需要遍历所有花朵对,时间复杂度为 O(F2)O(F^2),因此总的时间复杂度为 O(F2log(1e9))O(F^2 \log(1e9))
    • 空间复杂度:主要用于存储并查集的父节点数组,空间复杂度为 O(F)O(F)
    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    // 花朵的坐标结构体
    struct Flower {
        int x, y;
    };
    
    // 计算两点间的距离
    double distance(const Flower& a, const Flower& b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    // 并查集类
    class UnionFind {
    private:
        vector<int> parent;
    public:
        UnionFind(int n) {
            parent.resize(n);
            for (int i = 0; i < n; ++i) {
                parent[i] = i;
            }
        }
    
        int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
    
        void unite(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX != rootY) {
                parent[rootX] = rootY;
            }
        }
    
        bool connected(int x, int y) {
            return find(x) == find(y);
        }
    };
    
    // 检查是否可以使用给定的最大距离将花朵分成 B 组
    bool check(const vector<Flower>& flowers, double maxDist, int B) {
        int n = flowers.size();
        UnionFind uf(n);
    
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (distance(flowers[i], flowers[j]) <= maxDist) {
                    uf.unite(i, j);
                }
            }
        }
    
        int groups = 0;
        for (int i = 0; i < n; ++i) {
            if (uf.find(i) == i) {
                ++groups;
            }
        }
    
        return groups <= B;
    }
    
    int main() {
        int F, B;
        cin >> F >> B;
    
        vector<Flower> flowers(F);
        for (int i = 0; i < F; ++i) {
            cin >> flowers[i].x >> flowers[i].y;
        }
    
        double left = 0, right = 1e9;
        while (right - left > 1e-6) {
            double mid = (left + right) / 2;
            if (check(flowers, mid, B)) {
                right = mid;
            } else {
                left = mid;
            }
        }
    
        cout << fixed << setprecision(2) << right << endl;
    
        return 0;
    }
    
    • 1

    信息

    ID
    842
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    8
    已通过
    1
    上传者