1. 程式人生 > >【NOIP2018模擬賽2018.10.17】刺客信條(AC)

【NOIP2018模擬賽2018.10.17】刺客信條(AC)

題目

在這裡插入圖片描述


題解

–這道題可以用二分,或者是並查集
但是怎麼寫check()是個大問題
首先,你可以發現,對於一個人,他能控制的範圍是個圓
如果不能到終點的情況就是一串圓相連,把起點和終點隔開
所以可以用並查集維護連通性
當邊界剛好聯通的那個就是最遠的距離


程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using
namespace std; const int MAXN=2005; int x,y,n; int a[MAXN],b[MAXN]; struct hehe{ int u,v; long long l; }edge[MAXN*MAXN]; int cnt; int f[MAXN]; long long ans; void add_1(int i){ cnt++; edge[cnt].u=i; edge[cnt].v=n+1; edge[cnt].l=1ll*min(a[i],y-b[i])*2; edge[cnt].l*=edge[cnt].l; cnt++; edge[
cnt].u=i; edge[cnt].v=n+2; edge[cnt].l=1ll*min(x-a[i],b[i])*2; edge[cnt].l*=edge[cnt].l; } void add_2(int i,int j){ cnt++; edge[cnt].u=i; edge[cnt].v=j; edge[cnt].l=1ll*(a[i]-a[j])*(a[i]-a[j])+1ll*(b[i]-b[j])*(b[i]-b[j]); } bool comp(const hehe &a,const hehe &b){ return a.l<b.l;
} int get(int x){ if(x==f[x]) return x; return f[x]=get(f[x]); } int main(){ cin>>x>>y>>n; for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); for(int i=1;i<=n;i++){ add_1(i); for(int j=1;j<i;j++) add_2(i,j); } sort(edge+1,edge+1+cnt,comp); for(int i=1;i<=n+2;i++) f[i]=i; for(int i=1;i<=cnt;i++){ int fu=get(edge[i].u); int fv=get(edge[i].v); if(fu==fv) continue; f[fu]=fv; ans=max(ans,edge[i].l); if(get(n+1)==get(n+2)) break; } printf("%.2lf",(double)sqrt(ans)/2); return 0; }