洛谷P1661 扩散 题解

本题做法

  • 二分答案+并查集。

思路

二分答案\(x\),使用并查集判断在\(x\)时刻内是否能够形成连通块。

若任意2点的曼哈顿距离(即\(x\)坐标和\(y\)坐标的差值之和)小于等于\(2x\)(因为2个点是同时在扩散的),则这2点在\(x\)时刻内是可以形成连通块的。将2点在并查集内连边在一起。在结束后判断是否只有1个连通块,若只有1个,则在\(x\)时刻内是可以满足条件的,否则不可以。

最后输出结果(\(r\))。

代码

#include <bits/stdc++.h>
#define endl '\n'
#define ll long long

using namespace std;

const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const int N = 55;

struct coord {
    int x;
    int y;
} p[N];

int n, fat[N] /*并查集*/;

int getf(int x) {
    if (fat[x] == x)
        return x;
    return (fat[x] = getf(fat[x]));
}

bool check(int x) {
    for (int i = 1; i <= n; i++)
        fat[i] = i;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            int dis = abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y);
            if (dis <= 2 * x) {
                int fi = getf(i), fj = getf(j);
                if (fi != fj)
                    fat[fi] = fj;
            }
        }
    }
    int s = 0;
    for (int i = 1; i <= n; i++)
        s += (fat[i] == i);
    return s == 1;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> p[i].x >> p[i].y;
    int l = 0, r = 1000000001;
    while (l + 1 < r) {
        int mid = l + ((r - l) >> 1);
        if (check(mid))
            r = mid;
        else
            l = mid;
    }
    cout << r << endl;
    return 0;
}
posted @ 2025-03-02 13:15  2789617221guo  阅读(28)  评论(0)    收藏  举报