JZOJ 5401. 【NOIP2017提高A组模拟10.8】Star Way To Heaven

18 篇文章 0 订阅
15 篇文章 0 订阅

Description

Description

Input

Input

Output

Output

Sample Input

10 5 2
1 1
2 3

Sample Output

1.11803399

Data Constraint

Data Constraint

Solution

  • 首先二分答案 mid ,那么星星就变成了一个个不能触及的半径为 mid 的圆。

  • 此时两边界也向中间缩了 mid ,如果两边界通过一些圆连在了一起,则说明不可行。

  • 于是我们考虑并查集,把能相连的点(相距小于 mid2 )并到一起。

  • 同时每个点也判断一下是否能与边界并到一起。若最后两边界属于同一集合则说明不可行。

  • 但点两两之间判断是否相连是很浪费时间的,时间复杂度达到了 O(K2 logK)

  • 对于每个点,我们只需判断与它相邻的四个点即可(左上、左下、右上、右下)。

  • 这些点可以预处理出,时间复杂度就降到了 O(K2)

Code

#include<cstdio>
#include<cmath>
using namespace std;
const int N=6003;
const double eps=1e-8;
struct data
{
    double x,y;
}a[N];
int n,m,k;
double ans;
int f[N],g[N][4];
inline int read()
{
    int X=0,w=1; char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
inline int get(int x)
{
    return (f[x]==x)?x:f[x]=get(f[x]);
}
inline double calc(int x,int y)
{
    return sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y));
}
inline bool check(double x)
{
    for(int i=1;i<=k+2;i++) f[i]=i;
    for(int i=k;i;i--)
        for(int j=0;j<4;j++)
            if(g[i][j] && calc(i,g[i][j])<=x)
            {
                int f1=get(i),f2=get(g[i][j]);
                if(f1!=f2) f[f1]=f2;
            }
    for(int i=1;i<=k;i++)
    {
        if(a[i].y<=x)
        {
            int f1=get(i),f2=get(k+1);
            if(f1!=f2) f[f1]=f2;
        }
        if(m-a[i].y<=x)
        {
            int f1=get(i),f2=get(k+2);
            if(f1!=f2) f[f1]=f2;
        }
    }
    return get(k+1)!=get(k+2);
}
int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=k;i++) a[i].x=read(),a[i].y=read();
    for(int i=1;i<=k;i++)
        for(int j=1;j<=k;j++)
        if(i!=j)
        {
            double x=calc(i,j);
            if(a[j].x<=a[i].x && a[j].y<=a[i].y && (!g[i][0] || x<calc(i,g[i][0]))) g[i][0]=j;
            if(a[j].x<=a[i].x && a[j].y>a[i].y && (!g[i][1] || x<calc(i,g[i][1]))) g[i][1]=j;
            if(a[j].x>a[i].x && a[j].y>a[i].y && (!g[i][2] || x<calc(i,g[i][2]))) g[i][2]=j;
            if(a[j].x>a[i].x && a[j].y<=a[i].y && (!g[i][3] || x<calc(i,g[i][3]))) g[i][3]=j;
        }
    double l=0,r=m;
    while(r-l>=eps)
    {
        double mid=(l+r)/2;
        if(check(mid*2)) l=mid+eps,ans=mid; else r=mid-eps;
    }
    printf("%.8lf",ans);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值