二分+并查集【bzoj3007】[SDOI2012]拯救小云公主

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的最远距离,精确到小数点后两位。

这里的距离指的是欧几里德距离

首先很容易看出是二分答案

我们可以看成是以每个\(boss\)为圆心作一个半径为\(r\)的圆,我们想要求的就是让这些圆尽可能大,并且不能影响我们从\((1,1)\)到\((n,m)\)。(不能覆盖)

直接考虑边界条件\((n,1)\)和\((1,m)\)如果这两个点没有被覆盖,那我必然可以到达\((n,m)\)

PS:这里的判断条件不是同时判断。

这样用\(||\)判断,可以达到我们边界不被封锁的情况。

并查集维护连通即可。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define eps 1e-4
#define R register

using namespace std;

const int gz=3e3+8;

inline void in(R int &x)
{
    R int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}

int nn,n,m,f[gz];

struct cod
{
    int x,y;
}bos[gz];

int find(R int x){return f[x]==x?x:f[x]=find(f[x]);}

inline double xx(R double x)
{
    return x*x;
}

inline double dis(R int i,R int j)
{
    return xx(bos[i].x-bos[j].x)+xx(bos[i].y-bos[j].y);
}

inline bool ok(R double r)
{
    for(R int i=0;i<=nn+1;i++)f[i]=i;
    for(R int i=1;i<=nn;i++)
    {
        for(R int j=1;j<i;j++)
        {
            if(dis(i,j)<=xx(2*r))
            {
                R int fa=find(i),fb=find(j);
                if(fa!=fb)f[fa]=fb;
            }
        }
        if(bos[i].x-r<=1 or bos[i].y+r>=m)
        {
            R int fa=find(i),fb=find(0);
            if(fa!=fb)f[fa]=fb;
        }
        if(bos[i].x+r>=n or bos[i].y-r<=1)
        {
            R int fa=find(i),fb=find(nn+1);
            if(fa!=fb)f[fa]=fb;
        }
    }
    return find(0)!=find(nn+1);
}

int main()
{
    in(nn),in(n),in(m);
    for(R int i=1;i<=nn;i++)
        in(bos[i].x),in(bos[i].y);
    R double ll=0,rr=min(n,m);
    while(fabs(ll-rr)>eps)
    {
        R double mid=(ll+rr)/2;
        if(ok(mid))ll=mid;
        else rr=mid;
    }
    printf("%.2f",ll);
}

原文地址:https://www.cnblogs.com/-guz/p/9975749.html

时间: 2024-10-13 16:55:56

二分+并查集【bzoj3007】[SDOI2012]拯救小云公主的相关文章

【bzoj3007】拯救小云公主 二分+对偶图+并查集

题目描述 英雄又即将踏上拯救公主的道路…… 这次的拯救目标是——爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1的时候,他明白这就是一个不可能完成的任务. 但他不死心,他在想,能不能避开boss去拯救公主呢,嘻嘻. Boss的洞穴可以看成一个矩形,英雄在左下角(1,1),公主在右上角(row,line).英雄为了避开boss,当然是离boss距离越远越好了,所以英雄决定找一条路径使到距离boss的最短距离

P2498 [SDOI2012]拯救小云公主

\(\color{#0066ff}{ 题目描述 }\) 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1的时候,他明白这就是一个不可能完成的任务. 但他不死心,他在想,能不能避开boss去拯救公主呢,嘻嘻. Boss的洞穴可以看成一个矩形,英雄在左下角(1,1),公主在右上角(row,line).英雄为了避开boss,当然是离boss距离越远越好了,所

[SDOI2012]拯救小云公主

题目链接: 题目 分析 最大的最小最小的最大 一看就非常的二分 考虑二分之后转化成判定联通问题 于是可以考虑奶酪 直接维护联通好像很\(GG\),正难则反考虑维护不连通 什么时候不连通,发现当左上角和右下角分在两个块里面就凉了 当上和右边或上和下边联通的时候左上角和右下角被分割在两块 另外两种情况同理 于是并查集仿照奶酪维护一下,如果四种都没联通说明可以走到 外面再套个二分 复杂度\(O(n ^ 2 * log(n))\) 此代码吸氧可过 #include<bits/stdc++.h> #de

【BZOJ】【3007】拯救小云公主

思路题 我的naive的做法是二分答案+判定是否有路径可走……但是没有正确理解[走的方向任意]这句话…… 其实就是说想咋走咋走= =360°无死角乱走…… 所以其实是个平面上的问题…… 我们可以换个方向来考虑……二分一个答案,判断英雄走到/走不到公主那里,是不是就等价于,boss控制的区域连起来了使得英雄走不到公主那里了?(狼抓兔子的即视感) 所以我们可以转化成从上边&左边,在boss之间走,使得走到下边&右边 路径上最大的一条边(边权代表着如果英雄从这两个boss之间经过,离两个boss

BZOJ:4219: 跑得比谁都快 3007: 拯救小云公主

4219: 跑得比谁都快 3007: 拯救小云公主 后一道是前一道的弱化版. 如果考虑一下二分答案再判定,判定的过程无非就是把每个点变成一个以答案为半价的圆,然后如果左上和右下被切开了肯定就不合法,那就变成1001里面那种对偶图,跑一下spfa就好. 再看其实就不需要二分答案了,把各个boss连接起来,二分的答案达到边权一半时这两个圆就相交.整条路径会在达到最大边权的时候完全连通,那么最大边权最小的路径就是答案. 所以就三角剖分+最小生成树,至于三角剖分我选择拉模版. 貌似得用long doub

bzoj3007: 拯救小云公主

Description 英雄又即将踏上拯救公主的道路…… 这次的拯救目标是——爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1的时候,他明白这就是一个不可能完成的任务. 但他不死心,他在想,能不能避开boss去拯救公主呢,嘻嘻. Boss的洞穴可以看成一个矩形,英雄在左下角(1,1),公主在右上角(row,line).英雄为了避开boss,当然是离boss距离越远越好了,所以英雄决定找一条路径使到距离bo

[BZOJ 3007] 拯救小云公主 对偶图

题意 给定 $r, c$ , 以及矩形 $(1, 1), (r, c)$ 内的 $n$ 个点组成的点集 $S$ . 求一条从 $(1, 1)$ 到 $(r, c)$ 的矩形内的路径, 最大化路径到 $S$ 中的点的最小距离. $n \le 3000$ . 分析 考虑二分答案 $x$ , 判定: 当前有 $n$ 个半径为 $x$ 的圆, 是否能从 $(1, 1)$ 走到 $(r, c)$ . 原图存在路径, 当且仅当对偶图不存在将 $(1, 1)$ 与 $(r, c)$ 割开的边集, 即不存在从左

POJ 1797 Heavy Transportation(二分+并查集/kruskal)

Heavy Transportation Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 24398   Accepted: 6472 Description Background Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man

P2898 [USACO08JAN]haybale猜测Haybale Guessing 二分 + 并查集

二分 + 并查集 题目链接:https://www.luogu.org/problemnew/show/2898 题目大意: 给一段长度为n,每个位置上的数都不同的序列a[1..n]和q和问答, 每个问答是(x, y, r)代表RMQ(a, x, y) = r, 要你给出最早的有矛盾的那个问答的编号. 首先,要你求的是出现矛盾的,那什么时候才会出现矛盾呢? 可以总结为两种情况: ①之前已更新这个区间最小值为x,又要更新此区间的子区间(或这个区间)的最小值为更小的数. 这样~ (黑色是已更新区间,