Fork me on GitHub

bzoj 1821 部落划分

评测:http://www.lydsy.com/JudgeOnline/problem.php?id=1821
这里写图片描述
分析一下题目:
因为最后答案是距离最近的部落的距离最远,即尽量把短的边合并进部落中。
一开始可以看做n个部落,将边排一遍序,用克鲁斯卡尔从最小的边开始将两端的点合并(如果不在一个集合中),每合并一次,集合数目就 -1,直到剩下k个部落,那么下一条两端没有在一个集合中的边就是要求的答案。
和口袋(云彩)的天空(洛谷上的)那个题差不多。

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cmath>
#define P(x) (x)*(x) 
using namespace std;
int n,k;
struct H{
    int x,y;double len;
}a[600009];int cnt;
double X[1009],Y[1009];
int f[1009];
bool cmp(H p,H q){return p.len<q.len;}
int find(int x)
{
    if(x==f[x]) return f[x];
    return f[x]=find(f[x]);
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&X[i],&Y[i]);
    for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) 
    a[++cnt].x=i,a[cnt].y=j,a[cnt].len=sqrt(P(X[i]-X[j])+P(Y[i]-Y[j]));
    sort(a+1,a+cnt+1,cmp);
    for(int i=1;i<=n;i++) f[i]=i;
    int p=0;
    while(n>k)
    {
        p++;
        int u=find(a[p].x),v=find(a[p].y);
        if(u!=v) f[u]=v,n--;    
    }
    while(p<=cnt)
    {
        p++;
        int u=find(a[p].x),v=find(a[p].y);
        if(u!=v){printf("%.2lf",a[p].len);return 0;} 
    } 
    return 0;       
} 
posted @ 2017-09-24 17:48  primes  阅读(144)  评论(0编辑  收藏  举报