题目大意:给定平面上的n个点,要求将这n个点划分为k个集合,使划分后任意两个集合中最近两点的距离的最大值最小,输出这个最小值
考虑这n个点之间所有的连边 我们要让长边保留 就尽量选取短边链接
于是就是求加入n-k条边的最小生成森林 由于输出下一个最小值 因此Kruskal加入第n-k+1条边时输出边权即可
#include <cmath> #include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define M 1100 using namespace std; struct point{ int x,y; void Read() { scanf("%d%d",&x,&y); } }points[M]; struct edge{ int x,y; double dis; edge() {} edge(int _,int __,double ___): x(_),y(__),dis(___) {} bool operator < (const edge &e) const { return dis < e.dis; } }edges[1001001]; int n,m,k; double Distance(const point &p1,const point &p2) { return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) ); } namespace Union_Find_Set{ int fa[M]; inline void Union(int x,int y) { fa[x]=y; } int Find(int x) { if(!fa[x]||fa[x]==x) return fa[x]=x; return fa[x]=Find(fa[x]); } } double Kruskal(int temp) { using namespace Union_Find_Set; int i; sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int x=Find(edges[i].x); int y=Find(edges[i].y); if(x==y) continue; Union(x,y); if(!--temp) return edges[i].dis; } return 0; } int main() { int i,j; cin>>n>>k; for(i=1;i<=n;i++) points[i].Read(); for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j) edges[++m]=edge(i,j,Distance(points[i],points[j]) ); cout<<fixed<<setprecision(2)<<Kruskal(n-k+1)<<endl; }
BZOJ 1821 JSOI2010 部落划分 Group Kruskal
原文地址:http://blog.csdn.net/popoqqq/article/details/42271079