分析

首先看题目发现这是一个连通性问题,就是在某个半径下一些塔的控制范围有重叠部分,两塔有重叠就说明它们连成了一片,同理若某塔控制了海滩边缘,这一侧边缘也与它相连,海滩受保护当且仅当左右摊联通,显然这是一个满足二分的东西,半径越大可连的边单调不降,但我们并不需要二分,只需要一次找出所有边,然后按边权从小到大跑,每次将起终点相连,当左右海滩相连时,当前处理的那一条边的边权即为答案。

code


#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
	char c;
	int f=1;
	res=0;
	c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
	res*=f;
}
int n,m;
double x[805],y[805];
int tot;
struct edge{
	int fr,to;
	double w;
}e[700005];
inline int add(int qq,int mm,double bq){
	e[++tot].to=mm;
	e[tot].fr=qq;
	e[tot].w=bq;
}
inline bool cmp(edge aa,edge bb){
	return aa.w<bb.w;
}
int fa[810];
inline int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
double ans;
double dis(int xx,int yy){
	return sqrt((x[xx]-x[yy])*(x[xx]-x[yy])+(y[xx]-y[yy])*(y[xx]-y[yy]))/2.0;
}
int main()
{
	read(n);read(m);
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i];
		add(i,m+1,x[i]);
		add(i,m+2,n-x[i]);
	}
	for(int i=1;i<=m+2;i++)fa[i]=i;
	for(int i=1;i<=m;i++){
		for(int j=i+1;j<=m;j++){
			add(i,j,dis(i,j));
		}
	}
	sort(e+1,e+tot+1,cmp);
	for(int i=1;i<=tot;i++){
		ans=e[i].w;
		int kx=find(e[i].fr),ky=find(e[i].to);
		if(kx==ky)continue;
		fa[kx]=ky;
		if(find(m+1)==find(m+2))break;
	}
	printf("%.2lf",ans);
	return 0;
}

posted on 2021-10-31 09:32  漠寒·  阅读(37)  评论(0编辑  收藏  举报