BZOJ1821 部落划分[最小生成树]
方法一:套路性的,二分距离,然后把距离点对距离小于答案的边都联通起来,然后看集合数量超过k说明答案小,增大,否则减小。
方法二:贪心,类kruskal。n个点,k个连通块,则需要有效连接(同一个块内的点相互连接不算)n-k次。那么用类似kruskal的证明过程发现最小的边一定要联通使得集合与集合间距离尽量大,连完n-k条边之后的第n-k+1条连接不同连通块的点对距离即为所求。
code是我一年前写的,现在我只能想出第一种方法,越学越退步,自闭嘤嘤嘤。
1 //注:原来代码被我想复杂了,自己对比。 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef double db; 5 const int N=1000+3; 6 inline int read(){ 7 int x=0,f=0;char ch; 8 while(!isdigit(ch=getchar()))if(ch=='-') f=1; 9 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar(); 10 return f?-x:x; 11 } 12 struct edge{ 13 int u,v;db dis; 14 }e[N*N]; 15 int X[N],Y[N],f[N]; 16 int n,k,m,cnt; 17 18 bool cmp(edge a,edge b){return a.dis<b.dis;} 19 int Find(int x){if(f[x]!=x) f[x]=Find(f[x]);return f[x];} 20 21 int main(){ 22 n=read(),k=read(); 23 for(register int i=1;i<=n;++i){ 24 X[i]=read(),Y[i]=read();f[i]=i; 25 for(register int j=1;j<i;++j) e[++m].dis=sqrt((Y[i]-Y[j])*(Y[i]-Y[j])+(X[i]-X[j])*(X[i]-X[j])),e[m].u=i,e[m].v=j; 26 } 27 sort(e+1,e+m+1,cmp); 28 for(register int i=1;i<=m;++i){ 29 int fx=Find(e[i].u),fy=Find(e[i].v); 30 if(fx!=fy){ 31 f[fy]=fx,++cnt; 32 if(cnt==n-k+1){printf("%.2f\n",e[i].dis);return 0;} 33 } 34 } 35 return 0; 36 }