Description
故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成为了杰出的刺客大师。刺客组织在他的带领下,为被剥削的平民声张正义,赶跑了原本统治意大利的圣殿骑士首领-教皇亚历山大六世。在他的一生中,经历了无数次惊心动魄、扣人心弦的探险和刺杀。
这次的故事就是他暗杀一位作恶多端的红衣主教。红衣主教可以吸取他周围人的生命力量,而他的红衣教徒也拥有这个力量。红衣主教的家是一个x*y 的长方形房间,也就是说,他的家的四个角坐标分别为(0,0)(x,0)(0,y)(x,y)。教堂的门在(0,0) ,而红衣主教就在 (x,y)的卧室休息。他的家中还有n个守护着他的红衣教徒,站在(ai,bi)。Ezio想要趁主教休息时,从门进入潜入到他的卧室刺杀他,因为主教休息时会脱下红衣,这样吸取生命的力量就消失了。可是守卫他的红衣教徒依然很危险,离红衣教徒太近就会被吸取生命。因此,Ezio想知道,在能刺杀主教的前提,从门到他的卧室的路上,他最远和离他最近的红衣教徒保持多远的距离。注意:教徒都在房间里。
Input
第一行三个整数x,y,n。之后n行,每行两个整数ai,bi ,意义见题目描述。
Output
一行一个数D,表示Ezio能保持的最大距离,保留两位小数。
Data Constraint
数据范围
对 10%的数据n<=10,
对 30%的数据n<=100
对 100%的数据n<=2000
保证输入合法,x,y属于[1,10^6].
题解
一眼看下去,好像是二分一个值然后,判断是否合法。
其实并不用这样,可以知道只要上边界或者左边界跟另外两个边界连通之后,从左下角就不能走到右上角了。
先将所有边按照边权排序,然后不断连边,知道边界连通,
然后最后连上去的那一条边的边权就是最终的答案了。
code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define N 2003
#define db double
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
struct node
{
int x,y;
db v;
}t[N*N];
int n,x[N],y[N],f[N],xx,yy,tot,ans;
void ins(int x,int y,db v)
{
t[++tot].x=x;t[tot].y=y;
t[tot].v=v;
}
bool cmp(node a,node b){return a.v<b.v;}
int get(int x){return f[x]=(f[x]^x)?get(f[x]):x;}
int main()
{
freopen("AC.in","r",stdin);
freopen("AC.out","w",stdout);
read(xx);read(yy);read(n);
for(int i=1;i<=n;i++)
{
read(x[i]);read(y[i]);f[i]=i;
ins(n+1,i,y[i]);
ins(n+1,i,xx-x[i]);
ins(n+2,i,x[i]);
ins(n+2,i,yy-y[i]);
for(int j=1;j<i;j++)
ins(i,j,sqrt((db)(x[i]-x[j])*(x[i]-x[j])+(db)(y[i]-y[j])*(y[i]-y[j]))/2);
}
f[n+1]=n+1;f[n+2]=n+2;
sort(t+1,t+1+tot,cmp);
for(ans=1;get(n+1)^get(n+2);ans++)f[get(t[ans].x)]=get(t[ans].y);
printf("%.2lf",t[ans-1].v);
return 0;
}