1. 程式人生 > >【BZOJ1821】[JSOI2010]部落劃分(二分,並查集)

【BZOJ1821】[JSOI2010]部落劃分(二分,並查集)

【BZOJ1821】[JSOI2010]部落劃分(二分,並查集)

題面

BZOJ
洛谷

題解

二分答案,把距離小於二分值的點全部並起來,\(\mbox{check}\)一下是否有超過\(K\)個集合就好了。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define MAX 1010
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int f[MAX],x[MAX],y[MAX],n,K;
double Sqr(double x){return x*x;}
double Dis(int i,int j){return sqrt(Sqr(x[i]-x[j])+Sqr(y[i]-y[j]));}
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
bool check(double mid)
{
    for(int i=1;i<=n;++i)f[i]=i;
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            if(Dis(i,j)<=mid)f[getf(j)]=getf(i);
    int tot=0;
    for(int i=1;i<=n;++i)if(i==getf(i))++tot;
    return tot>=K;
}
int main()
{
    n=read();K=read();
    for(int i=1;i<=n;++i)x[i]=read(),y[i]=read();
    double l=0,r=2e4;
    while(r-l>1e-4)
    {
        double mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid;
    }
    printf("%.2lf\n",l);
    return 0;
}