题目描述
WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和仓库总是被敌方派人偷袭。于是,WLP动用了他那丰满且充实的大脑(或许更偏向前者),想出了一个好主意,他把海滩分成垂直于海岸线的若干列,在其中的几列上放置几个信号塔,试图来监视整个海滩。然而,WLP是一个非常心急的人,他把信号塔建好后才发现还需给信号塔供能,它们才能投入使用(这不是废话么),它们都有一个工作半径,一个圆形区域里的所有敌人都逃不过它们的监视,不过,WLP发现,敌人们非常狡猾,除非他将道路完全封死,否则WLP的敌人可以走过一条任意弯曲的路(不一定走整点,但是不会出第0列和第N列构成的边界)来偷他的东西。
于是,WLP就思考了:到底需要给每个信号塔多大的工作半径,才能将从海滩到内地的路径完全封死呢?他再次动用了他那丰满且充实的大脑,想了一堂数学课,终于,还是没想出来。于是,他向LZZ神犇求助(额……C_SUNSHINE的身份是不是暴露了)。
终于,在WLP:“%^!*@#!*(*^!*#@$^&(此处省略无数卖萌场景)”的哀求下,LZZ神犇写了一个程序,在1s内就解决了问题。但是,邪恶的LZZ神犇决定要将这个难题共享给无数无辜的OIer,所以,现在轮到你了。
输入输出格式
输入格式:
第一行两个整数N和M:表示海滩被WLP分成的列数0-N和信号塔个数。
第2-M+1行:每行两个数Xi,Yi表示1-M号信号塔所在的列数和离开海滩的距离。
输出格式:
一行一个实数,表示最小的工作半径,保留两位小数。
输入输出样例
输入样例#1:
【输入样例1】 5 5 1 5 3 5 5 5 4 30 2 15 【输入样例2】 100 2 30 50 90 100
输出样例#1:
【输出样例1】 1.00 【输出样例2】 39.05
说明
对于10%的数据:1≤M≤10,1≤Yi≤100;
对于30%的数据:1≤M≤50,1≤Yi≤1,000;
对于80%的数据:1≤M≤500,1≤Yi≤1,000;
对于100%的数据:1≤M≤800,1≤N≤1000,1≤Xi≤N,1≤Yi≤100,000.
【样例解释】
注意,封锁海滩是指,敌人的深入程度是有限制的,若敌人绕过了所有的信号塔,并且可以长驱直入,那么就说明道路没有完全封锁。
思路:图的转化+排序+并查集
先把数据转化为图中的边(包括点点边和点界边),然后给边排序,加边直到两边界相连(0-m+1)。
代码实现:
1 #include<cmath> 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 #define maxm 1010 6 using namespace std; 7 int n,m,l,a,b,f[maxm]; 8 double ans,x[maxm],y[maxm]; 9 struct edge{int q,z;double v;}e[maxm*maxm]; 10 inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);} 11 inline double dis(int i,int j){return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))/2;} 12 inline bool cmp(const edge&a,const edge&b){return a.v<b.v;} 13 int main(){ 14 scanf("%d%d",&n,&m); 15 for(int i=1;i<=m+1;i++) f[i]=i; 16 for(int i=1;i<=m;i++) scanf("%lf%lf",&x[i],&y[i]); 17 for(int i=1;i<m;i++) 18 for(int j=i+1;j<=m;j++) 19 e[l++]=(edge){i,j,dis(i,j)}; 20 for(int i=1;i<=m;i++){ 21 e[l++]=(edge){0,i,x[i]}; 22 e[l++]=(edge){i,m+1,n-x[i]}; 23 } 24 sort(e,e+l,cmp); 25 for(int i=0;i<l;i++){ 26 a=find(e[i].q),b=find(e[i].z); 27 f[b]=a;ans=e[i].v; 28 if(find(0)==find(m+1)) break; 29 } 30 printf("%.2lf\n",ans); 31 return 0; 32 }
竟然一直没有勇气做。
题目来源:洛谷