这道题可以用二分答案做,但是我个人认为最小生成树做更为简洁。其实最小生成树并不准确,应该是最小生成森林。
因为我们只要把所有部落连成k个块,然后让最近的块最远,所以我们肯定是连长度最小的边,那就是最小生成树咯。我们先建出一张完全图,之后跑一遍kruskal,每次如果属于不同集合的话把森林个数-1,直到满足要求。
这题有一个坑,就是你在满足条件之后,再枚举的边可能是在集合之内,所以我们还得继续枚举一个集合之外的边,其边权就是答案。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') using namespace std; typedef long long ll; const int M = 1000005; const int N = 1005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,from; double dis; bool operator < (const edge &g) const { return dis < g.dis; } }e[M<<1]; struct node { double x,y; }a[1005]; int n,k,fa[N],head[N],ecnt,cnt; double calc(int p,int q) { return sqrt((a[p].x - a[q].x) * (a[p].x - a[q].x) + (a[p].y - a[q].y) * (a[p].y - a[q].y)); } void add(int x,int y,double z) { e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].dis = z; e[ecnt].next = head[x]; head[x] = ecnt; } int getfa(int x) { return (fa[x] == x) ? x : fa[x] = getfa(fa[x]); } int main() { n = read(),k = read(); rep(i,1,n) fa[i] = i; rep(i,1,n) scanf("%lf%lf",&a[i].x,&a[i].y); rep(i,1,n) rep(j,i+1,n) add(i,j,calc(i,j)); sort(e+1,e+1+ecnt); rep(i,1,ecnt) { int r1 = getfa(e[i].from),r2 = getfa(e[i].to); if(r1 != r2) fa[r2] = r1,cnt++; if(cnt == n - k) break; } cnt++; while(cnt <= ecnt) { int r1 = getfa(e[cnt].from),r2 = getfa(e[cnt].to); if(r1 != r2) { printf("%.2lf ",e[cnt].dis); break; } cnt++; } return 0; }