• 【BZOJ3007】拯救小云公主 二分+几何+对偶图


    【BZOJ3007】拯救小云公主

    Description

        英雄又即将踏上拯救公主的道路……
        这次的拯救目标是——爱和正义的小云公主。
        英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss。当英雄意识到自己还是等级1的时候,他明白这就是一个不可能完成的任务。
        但他不死心,他在想,能不能避开boss去拯救公主呢,嘻嘻。
        Boss的洞穴可以看成一个矩形,英雄在左下角(1,1),公主在右上角(row,line)。英雄为了避开boss,当然是离boss距离越远越好了,所以英雄决定找一条路径使到距离boss的最短距离最远。
    Ps:英雄走的方向是任意的。
        你可以帮帮他吗?
        当英雄找到了美丽漂亮的小云公主,立刻就被boss包围了!!!英雄缓闭双眼,举手轻挥,白光一闪后使用了回城卷轴,回到了城堡,但只有小云公主回去了……因为英雄忘了进入回城的法阵了。

    Input

        第一行,输入三个整数,n表示boss的数目,row,line表示矩形的大小;
        接下来n行,每行分别两个整数表示boss的位置坐标。

    Output

        输出一个小数,表示英雄的路径离boss的最远距离,精确到小数点后两位。

    Sample Input

    1 3 3
    2 2
    输出样例1:
    1.00
    输入样例2:
    1 3 3
    3 1
    输出样例2:
    2.00

    Sample Output

    HINT

    100%数据,n<=3000;

    题解:离所有boss的最远距离为x可以转化为将所有boss看成半径为x的圆,且存在一条从左下角走到右上角的路径与所有圆不相交,即左下角和右上角在一个域中。这个距离显然是可以二分的。并且,左下角和右下角在一个域中等价于在对偶图中,左上角和右上角不连通。于是用并查集判断即可。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    const int maxn=3010;
    int n;
    int f[maxn];
    double mx,my;
    double x[maxn],y[maxn];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    double dis2(int a,int b)
    {
    	return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);
    }
    int find(int x)
    {
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    void uni(int a,int b)
    {
    	if(find(a)!=find(b))	f[f[a]]=f[b];
    }
    bool check(double r)
    {
    	int i,j;
    	for(i=1;i<=n+2;i++)	f[i]=i;	
    	for(i=1;i<=n;i++)
    	{
    		if(x[i]-r<=1||y[i]+r>=my)	uni(i,n+1);
    		if(x[i]+r>=mx||y[i]-r<=1)	uni(i,n+2);
    	}
    	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)	if(dis2(i,j)<=4*r*r)	uni(i,j);
    	return find(n+1)!=find(n+2);
    }
    int main()
    {
    	n=rd(),mx=rd(),my=rd();
    	int i;
    	for(i=1;i<=n;i++)	x[i]=rd(),y[i]=rd();
    	double l=0,r=mx+my,mid;
    	while(r-l>1e-4)
    	{
    		mid=(l+r)/2;
    		if(check(mid))	l=mid;
    		else	r=mid;
    	}
    	printf("%.2lf",l);
    	return 0;
    }
  • 相关阅读:
    Java实现多线程的四种实现方式
    电梯调度算法[转]
    带黑洞的随机游走问题
    深度学习印象
    使用jupyterthemes插件定制jupyter notebook界面
    tf.gfile
    中国象棋残局库构建[抄]
    Android(Linux)线路规程的使用
    Remote Displayer for Android V1.2
    Android开发资源汇总
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7391457.html
Copyright © 2020-2023  润新知