题目传送门:https://www.luogu.com.cn/problem/P4047 题解: 首先计算所有野人之间的距离 由于这些野人分成了k个部落,那么可以理解为将一颗生成树分成k个部分 由于一颗n个点的生成树需要连接 n-1 条边 将生成树分成k个部分需要扣除 k-1 条边 将野人当成一个点,所以对这些点需要连接 (n-1) - (k-1) = n-k 条边即可 由于题目需要求的是 两个部落之间的最小距离 那么这个最小距离即为我们分割时的最小边,即为最小生成树中 n-k+1 小的边 也就是说,我们选择了 n-k 条最小的边,但是 n-k+1 小的边没选 即成为了分割部落的那条边
代码及注释如下:
#include<iostream>
#include<cmath>
#include<algorithm>
#define two(x) (x)*(x)
using namespace std;
const int MAXN = 1e3+5;
struct node{
int u,v;
double w;
friend bool operator < (node a,node b) {
return a.w < b.w;
}
}a[MAXN*MAXN];
int dis[MAXN];
double x[MAXN],y[MAXN];
double cal(int i,int j) {
return sqrt(two(x[i]-x[j])+two(y[i]-y[j]));
}
int getf(int p) {
return dis[p]==p?p:dis[p]=getf(dis[p]);
}
int main() {
int n,k,cnt = 0;
cin>>n>>k;
for(int i = 1;i <= n;i++) {
cin>>x[i]>>y[i];
dis[i] = i;
}
for(int i = 1;i <= n;i++) {
for(int j = i+1;j <= n;j++) {
a[++cnt] = {i,j,cal(i,j)};
}
}
sort(a+1,a+1+cnt);
int num = 0;
double ans = 0;
for(int i = 1;i <= cnt;i++) {
node tmp = a[i];
if(getf(tmp.u)!=getf(tmp.v)) {
dis[getf(tmp.u)] = dis[getf(tmp.v)];
num++;
if(num==n-k+1) {
ans = a[i].w;
break;
}
}
}
printf("%.2f",ans);
return 0;
}
|