【bzoj1821】 JSOI2010Group 部落划分 二分+并查集

首先二分一下答案,然后距离小于答案的点对暴力连边,并查集判断即可。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define eps 1e-5
#define maxn 1010

using namespace std;

int x[maxn],y[maxn];
int f[maxn];
bool vis[maxn];
int n,k;

double dis(int i,int j)
{
	return sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(double)(y[i]-y[j])*(y[i]-y[j]));
}

int find(int x)
{
	if (f[x]==x) return x;
	else return f[x]=find(f[x]);
}

int check(double x)
{
	memset(vis,0,sizeof(vis));
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	    if (i!=j && dis(i,j)<x)
	    {
	    	int f1=find(i),f2=find(j);
	    	if (f1!=f2) f[f1]=f2;
	    }
	int num=0;
	for (int i=1;i<=n;i++)
	  if (!vis[find(i)]) vis[find(i)]=1,num++;
	return num;
}

int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
	double l=0,r=10000000000;
	while (r-l>eps)
	{
		double mid=(l+r)/2.0;
		if (check(mid)<k) r=mid;
		else l=mid;
	}
	printf("%.2lf\n",l);
	return 0;
}


你可能感兴趣的:(【bzoj1821】 JSOI2010Group 部落划分 二分+并查集)