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 }
View Code

 

posted @ 2019-10-15 14:44  Ametsuji_akiya  阅读(105)  评论(0编辑  收藏  举报