P4047 [JSOI2010]部落划分

题目描述

聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。

不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了 n 个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了 k 个部落!这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法:

对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。


思路

依次把两个最近的人划分到一个部落中去(若其中一个或两个人还属于其他部落,那么这两个部落合并),当最后剩下单独的k个人和部落的时候,这时候这其中的,相距最近的两个部落/部落和人的距离就是最重要的答案。

仔细观察,其实这就是一个最小生成树,建n-k条边的最小生成树,第n-k+1条边就是要的结果。


AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>

const int Maxn = 1005;

struct EDGE {
    int u, v;
    double w;

    EDGE(){}

    EDGE(int u, int v, double w):u(u), v(v), w(w){}

    bool operator < (const EDGE &x) const {
        return w < x.w;
    }
} e[Maxn * Maxn];

double a[Maxn][2];
int tot = 0, father[Maxn];

int Find(int x) {
    return father[x] == x ? x : father[x] = Find(father[x]);
}

void Union(int u, int v) {
    int ru = Find(u);
    int rv = Find(v);
    if (ru != rv) {
        father[ru] = rv;
    }
}

double getDis(int u, int v) {
    return sqrt(pow(a[u][0] - a[v][0], 2.0) + pow(a[u][1] - a[v][1], 2.0));
}

double Kruskal(int nv, int k) {
    for (int i = 0; i <= nv; i++) {
        father[i] = i;
    }
    int t = 0;
    double ans = 0;
    for (int i = 0; i < tot; i++) {
        int u = e[i].u;
        int v = e[i].v;
        if (Find(u) != Find(v)) {
            Union(u, v);
            t++;
            if (t == nv - k + 1) {
                ans = e[i].w;
            }
        }
    }
    return ans;
}

void solve() {
    int n, k;
    scanf("%d %d", &n, &k);
    for (int i = 0; i < n; i++) {
        scanf("%lf %lf", &a[i][0], &a[i][1]);
    }
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            e[tot++] = EDGE(i, j, getDis(i, j));
        }
    }
    std::sort(e, e + tot);
    double ans = Kruskal(n, k);
    printf("%.2f", ans);
}

int main() {
    solve();
    return 0;
}

posted @ 2021-02-18 15:58  牟翔宇  阅读(64)  评论(0编辑  收藏  举报