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;
}