[JSOI 2010] 部落划分

题目描述

原题戳我
对于任意一种部落划分的方法,都能够求出两个部落之间的距离,求出一种部落划分的方法,使靠得最近的两个部落尽可能远离(一共分成\(K\)个部落)。
例如,下面的左图表示了一个好的划分,而右图则不是。

题目解答

冷静分析

这题目太简单了
这题目一看就知道考并查集(其实是最小生成树变体),每次将距离最短的两个野村子部落融入到一个大部落中即可,然后剩\(K\)个集合时中断合并即可。

程序实现

在最小生成树的算法基础上加一个中断条件即可,至于距离,初始化稍微弄弄就行了,不过避开小数运算的好办法是保留平方,最后再开根即可。代码如下:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#define M 1000005
using namespace std;
int r = 0, x[1005], y[1005], n, k;
int ffind[1005];
struct E
{
    int a, b, dist;
}e[M];
bool cmp(E a, E b)
{
    return a.dist < b.dist;
}
int Dist(int i, int j)
{
    int a = x[j] - x[i], b = y[j] - y[i];
    return a * a + b * b;
}
int Find(int x)
{
    if(x != ffind[x])
        ffind[x] = Find(ffind[x]);
    return ffind[x];
}
inline void Together(int a, int b)
{
    ffind[Find(a)] = Find(b);
}
int main()
{
    int i, j;
    float ans;
    scanf("%d %d", &n, &k);
    for(i = 0; i < n; i++)
    {
        scanf("%d %d", &x[i], &y[i]);
        ffind[i] = i;
    }
    for(i = 0; i < n; i++)
        for(j = i + 1; j < n; j++)
        {
            e[r].a = i;
            e[r].b = j;
            e[r++].dist = Dist(i, j);
        }
    ans = n;
    sort(e, e + r, cmp);
    for(i = 0; i < r; i++)
        if(Find(e[i].a) != Find(e[i].b))
        {
            Together(ffind[e[i].a], ffind[e[i].b]);
            if(ans == k)
            {
                ans = sqrt(e[i].dist);
                break;
            }
            else ans --;
        }
    printf("%.2f", ans);
    return 0;
}

尾注

这可能是我写的很不认真的一个题解了

写在最后

感谢大家的关注和阅读。
本文章借鉴了少许思路,最后经过本人思考独立撰写此文章,如需转载,请注明出处。

posted @ 2018-05-13 14:30  孤独·粲泽  阅读(152)  评论(0编辑  收藏  举报