[JSOI2010]部落划分
题目:洛谷P4047
难度:普及/提高-
算法标签:生成树,并查集,二分答案
分析
要使每个部落之间的距离最大,我们可以采用贪心的策略,开始时看作每个居住点就是一个部落,每次将居住点距离最近的两个部落合并为一个部落,使各个部落之间的距离增大,合并至只剩k个部落,此时距离最近的两个部落之间的距离即是靠的最近的两个部落的最大距离。
显然我们需要合并n-k次,我们可以利用最小生成树,则树上第n-k+1长的边就是答案(注意不是图上第n-k+1长的边)。
思维难度不大,代码也比较好写
Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,k,tot,next,vis[1010],x[1010],y[1010];
double e[1010][1010],a[1010],dis[1010],Min=200000000;
double Distance(int a,int b){
return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
void Prim(){
for (int i=1;i<=n;i++){
dis[i]=200000000;
}
memset(vis,0,sizeof(vis));
dis[1]=0;
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if ((!vis[j])&&Min>dis[j]){
Min=dis[j];
next=j;
}
}
vis[next]=1;
a[++tot]=Min;
for (int j=1;j<=n;j++){
if ((!vis[j])&&dis[j]>e[next][j]){
dis[j]=e[next][j];
}
}
Min=200000000;
}
}
int main(){
scanf("%d %d",&n,&k);
for (int i=1;i<=n;i++){
scanf("%d %d",&x[i],&y[i]);
}
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
e[i][j]=e[j][i]=Distance(i,j);
}
}
Prim();
sort(a+2,a+n+1);
printf("%.2f\n",a[n-k+2]);//想一想为什么我这里写的是+2
return 0;
}