题目描述
输入
第一行包含两个整数N、K,分别描述野人居住点的数量和部落的数量。
接下来N 行,每行包含两个整数xi, yi,描述了一个居住点的坐标。
接下来N 行,每行包含两个整数xi, yi,描述了一个居住点的坐标。
输出
输出一行,为最优划分时,最近的两个部落的距离,精确到小数点后两位。
数据范围限制
Solution:
第一眼看到最小最大就秒写二分答案,结果爆精度了QAQ
正解有两个,一个是二分答案,不难发现单调性,二分结果,check的时候就判断各个点之间距离是否有小于二分出来答案的,有就把两点合并,运用并查集即可解决,但是要注意精度问题(详见代码)
另一个说是最小生成树,其实是运用类似于kruscal的思想,sort点点之间边的长度,然后从最小的开始判断,并使用并查集将它们合并,同时动态更新并查集数量,当并查集数量等于K即划分完毕
Code(二分答案):
1 #include<bits/stdc++.h>
2 using namespace std;
3 int N,K,Book[10005],Ans,fa[10005];
4 double Dis[1005][1005],X[10005],Y[10005];
5 int find(int x)
6 {
7 if(fa[x]==x) return x;
8 else return fa[x]=find(fa[x]);
9 }
10 bool Check(double T){
11 Ans=0;
12 for(int i=1;i<=N;i++) fa[i]=i;
13 for(int i=1;i<=N;i++) Book[i]=0;
14 // double Test=T+0.005;
15 for(int i=1;i<N;i++)
16 for(int j=i+1;j<=N;j++){
17 if(T>Dis[i][j]){
18 int fx=find(i),fy=find(j);
19 if(fx!=fy)
20 fa[fx]=fy;
21 }
22 }
23 for(int i=1;i<=N;i++){
24 int father=find(i);
25 if(!Book[father]){
26 Ans++;
27 Book[father]=1;
28 }
29 }
30 if(Ans>=K) return true;
31 else return false;
32
33 }
34 int main()
35 {
36 // freopen("tribe.in","r",stdin);
37 // freopen("tribe.out","w",stdout);
38 scanf("%d%d",&N,&K);
39 for(int i=1;i<=N;i++)
40 scanf("%lf%lf",&X[i],&Y[i]);
41 for(int i=1;i<=N;i++)
42 for(int j=1;j<=N;j++){
43 Dis[i][j]=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
44 // Dis[i][j]+=0.005;
45 }
46 double L=0.0001,R=200000000.00,Res=0;
47 while(L-R<=0.0001){
48 double Mid=(L+R)/2;
49 if(Check(Mid)){
50 Res=Mid;
51 L=Mid+0.0001;
52 }
53 else
54 R=Mid-0.0001;
55 }
56
57 printf("%.2lf",Res);
58 return 0;
59 }