图论最小生成树之 Star Way To Heaven(详细分析)

题目描述

w w w伤心的走上了 S t a r w a y t o h e a v e n Star way to heaven Starwaytoheaven
到天堂的道路是一个笛卡尔坐标系上一个 n ∗ m n*m nm的长方形通道 顶点在 ( ( (顶点在 ( 0 , 0 ) (0,0) (0,0) ( n , m ) ) (n,m)) (n,m))
w w w从最左边任意一点进入,从右边任意一点走到天堂,最左最右的距离为 n n n,上下边界距离为 m m m
其中长方形有 k k k S t a r Star Star,每个 S t a r Star Star都有一个整点坐标, S t a r Star Star的大小可以忽略不计。
每个 S t a r Star Star以及长方形上下两个边缘 ( ( (宇宙的边界 ) ) )都有引力,所以为了成功到达 h e a v e n heaven heaven w w w离他们越远越好。
请问小 w w w走到终点的路径上,距离所有星星以及边界的最小距离最大值可以为多少?

输入格式
一行三个整数 n , m , k n,m,k n,m,k
接下来 k k k行,每行两个整数 x i , y i xi,yi xi,yi表示一个点的坐标。

输出格式
一行一个数表示答案。保留到小数点后9位。

样例

样例输入
10 5 2
1 1
2 3
样例输出
1.118033989

算法分析

这道题可以二分,但是二分要超时,所以要用其他解法
1、所有点连接上边界(初始化)
图论最小生成树之 Star Way To Heaven(详细分析)_第1张图片
2、最小生成树连接相邻点进行prim,连接直接可以在prim里面连接。如果一个点的半径能够触碰到最下面,那就说明已经成功封闭了。
图论最小生成树之 Star Way To Heaven(详细分析)_第2张图片
3、最后输出最大连线距离,因为是两个点的半径,所以要除以2

注意:
这道题要用到坐标系上两点间长度

double Sqrt(edge x,edge y){
	return sqrt((x.xi-y.xi)*(x.xi-y.xi)+(x.yi-y.yi)*(x.yi-y.yi));
}

代码

#include
#include
#include
#include
#include
#include
using namespace std;
const int M=1e6+5;
struct edge{
	double xi,yi;
}G[M];
double dis[M];
bool flag[M];
int n,m;
double Sqrt(edge x,edge y){
	return sqrt((x.xi-y.xi)*(x.xi-y.xi)+(x.yi-y.yi)*(x.yi-y.yi));
}
double Prim(){
	double ans=0;
	for(int i=1;i<=m;i++){
		dis[i]=n-G[i].yi;
	}
	dis[m+1]=n;
	for (int i=1;i<=m+1;i++){
		int id=0;
		for(int j=1;j<=m+1;j++){
			if(!flag[j]&&(dis[j]<dis[id]||id==0)){
				id=j;
			}
		}
		ans=max(dis[id],ans);
		if(id==m+1) break;
		flag[id]=true;
		for(int j=1;j<=m;j++){
			dis[j]=min(dis[j],Sqrt(G[j],G[id]));
		}
		dis[m+1]=min(dis[m+1],G[id].yi);
	}
	return ans/2;
}
int main(){
	scanf("%*d%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lf %lf",&G[i].xi,&G[i].yi);
	}
	dis[m+1]=n;
	printf("%.9lf",Prim());
	return 0;
}

你可能感兴趣的:(最小生成树,图论)