P1783 海滩防御(图论+构造模型)

点我去A了这道题

感觉还是满有代表性的题,也不很难

r , c h e c k ? 第一想法是二分半径r,如何check?

2 r 当两个点的距离小于等于2r时就形成了一个整体

那我可以用并查集把他们合并。合并后拿新点再次开始枚举

2 r 如果某个点和新点距离小于2r我就再合并

, 结束后,看一下

. + \color{Red}Ⅰ.排序+并查集

m , m 2 其实m个点,点与点间只有m^2个距离

便 , 0 , m + 1 , 为了方便,我们构造0点代表左边界,m+1点,并且每个点和左边界和有边界连边

, 那直接按照距离排序,从小到大把点对用并查集合并

0 m + 1 , 什么时候0点和m+1点合并在一起了,什么时候就停下来

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
struct p{
	int x,y; double d;
	bool operator < (const p&tmp )	const{
		return d<tmp.d;
	}
}a[maxn]; int cnt=0,pre[maxn],n,m;
int find(int x){
	return x==pre[x]?x:pre[x]=find(pre[x]);
}
void join(int q,int w){
	pre[find(q)]=find(w);
}
double x[maxn],y[maxn];
double ju(int q,int w){
	return sqrt( (x[q]-x[w])*(x[q]-x[w])+(y[q]-y[w])*(y[q]-y[w]) );
}
int main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
		cin >> x[i] >> y[i];
	for(int i=0;i<=m+1;i++)	pre[i]=i;
	for(int i=1;i<=m;i++)
	{
		a[++cnt]=(p){0,i,2*x[i]};
		a[++cnt]=(p){m+1,i,2*(n-x[i])};
		for(int j=i+1;j<=m;j++)
			a[++cnt]=(p){i,j,ju(i,j)};
	}
	sort(a+1,a+1+cnt);
	for(int i=1;i<=cnt;i++)
	{
		join(a[i].x,a[i].y);
		if( find(0)==find(m+1) )
		{
			printf("%.2lf",a[i].d/2.0);
			return 0;
		}
	}
}

. \color{Red}Ⅱ.最短路或最小生成树

0 n 其实题目的本质就是要把0到n合并起来

0 n 那就从0到n跑最短路

, / 2 路径的花费是路上最大的边权,边权是点间的距离/2

0 n 或者直接最小生成树也可以把0点和n连接起来

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/107446791
今日推荐