洛谷 - 部落划分
原题:[P4047
题意:把n个地点划分成k个部分,给出每个点的坐标,要使每个部分之间的最短距离(两个部分中距离最近的两个地点的距离)尽量大。
分析:题意可以转化为,使一个部分间地点的距离尽量小,那么剩下的边,也就是部分间的距离自然就最大了,所以可以用kruskal。将边权从小到大排序,分前m-s+1条边权,前m-s条是各部分间地点的距离,最后1个是部分间的最短距离,即答案。
#include <bits/stdc++.h> using namespace std; const int N=1e3+5,M=N*N; int fa[N],n,k,x[N],y[N],cnt; double ans=0; struct node { int x,y; double z; }edge[M]; bool cmp(node a,node b) { if(a.z==b.z) return a.x<b.x; return a.z<b.z; } double cal(int x1,int y1,int x2,int y2) { return (double)sqrt((double)(x1-x2)*(x1-x2)+(double)(y1-y2)*(y1-y2)); } int find(int x) { if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void kruskal() { for(int i=1;i<=n;i++) fa[i]=i; int sum=0; for(int i=1;i<=cnt;i++) { int u=edge[i].x,v=edge[i].y; u=find(u),v=find(v); if(u!=v) { fa[u]=v; sum++; ans=max(ans,edge[i].z); } if(n-k+1==sum) { break; } } } int main() { scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) { cin>>x[i]>>y[i]; } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { edge[++cnt].x=i,edge[cnt].y=j; edge[cnt].z=cal(x[i],y[i],x[j],y[j]); } } sort(edge+1,edge+1+cnt,cmp); kruskal(); printf("%.2lf",ans); return 0; }

浙公网安备 33010602011771号