UVALive 6168 Fat Ninjas --二分小数+搜索

题意:一个NxN的网格地板,有一些激光束从天花板垂直射向地面的某个网格,一个圆要安全地从左走到右,不碰到上边界,下边界以及激光束,问这个圆的直径最大能达到多大。

分析:可以二分直径,关键在check函数的写法。可以讲这个圆缩成一个点,把圆的直径转化为激光的扫描范围,当激光范围完全堵死一条通道的时候,这个直径则是不可行的。怎样判断是否堵死一条通道了呢。每次check(dis)的时候,枚举激光束对,如果激光束之间距离小于dis,那么它们两个之间建一条边。还要注意处理边界,如果激光束范围与上边界或下边界相交,那么边界与这个激光束也建一条边。最后从一个边界dfs到另一个边界,如果能够dfs到,那么说明此时通道被堵死,此dis是不行的。继续二分就能得到答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
#define N 5007

struct node
{
    int x,y;
}p[N];

double d[N][N];
vector<int> G[N];
int n,L;
int vis[N],S,E;

double dis(node ka,node kb)
{
    return (double)sqrt((ka.x-kb.x)*(ka.x-kb.x)+(ka.y-kb.y)*(ka.y-kb.y));
}

int dfs(int u,int fa)
{
    if(u == E)
        return 1;
    vis[u] = 1;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(v == fa)
            continue;
        if(vis[v])
            continue;
        if(dfs(v,u))
            return 1;
    }
    return 0;
}

bool check(double D)
{
    S = 0;
    E = L+1;
    for(int i=0;i<=L+1;i++)
        G[i].clear();
    for(int i=1;i<=L;i++)
    {
        if(p[i].y < D)
            G[S].push_back(i);
        if(p[i].y + D > n)
            G[i].push_back(E);
        for(int j=i+1;j<=L;j++)
        {
            if(d[i][j] < D)
            {
                G[i].push_back(j);
                G[j].push_back(i);
            }
        }
    }
    memset(vis,0,sizeof(vis));
    if(dfs(S,-1))
        return 0;
    return 1;
}

int main()
{
    int i,j;
    while(scanf("%d%d",&n,&L)!=EOF && n)
    {
        for(i=1;i<=L;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        for(i=1;i<=L;i++)
            for(j=i+1;j<=L;j++)
                d[i][j] = dis(p[i],p[j]);
        double low = eps;
        double high = n;
        while(low+eps < high)
        {
            double mid = (low+high)/2.0;
            if(check(mid))
                low = mid;
            else
                high = mid;
        }
        printf("%.3lf\n",low);
    }
    return 0;
}

UVALive 6168 Fat Ninjas --二分小数+搜索,布布扣,bubuko.com

时间: 2024-12-21 17:40:11

UVALive 6168 Fat Ninjas --二分小数+搜索的相关文章

UVALive 6606 Meeting Room Arrangement 【搜索】

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4617 题目大意:现在有一个房间,租用的时间是1~12点,已知一些会议的开始时间和结束时间,问最多可以开多少会议(会议时间不可以冲突). 对结束时间进行一个排序,然后查找即可. #include<iostream> #include<algorith

UVALive - 3211 (2-SAT + 二分)

layout: post title: 训练指南 UVALive - 3211 (2-SAT + 二分) author: "luowentaoaa" catalog: true mathjax: true tags: - 2-SAT - 图论 - 训练指南 Now or later UVALive - 3211 题意 n架飞机,每架可选择两个着落时间.安排一个着陆时间表,使得着陆间隔的最小值最大 题解 二分查找最大值P,每次都用2-SAT判断是否可行. #include<bits

hiho_1139_二分+bfs搜索

题目 给定N个点和M条边,从点1出发,寻找路径上边的个数小于等于K的路径,求出所有满足条件的路径的路径中最长边长度的最小值. 题目链接:二分     最小化最大值,考虑采用二分搜索.对所有的边长进行排序,二分,对每次选择的边长,判断是否存在一条路径满足路径上所有的边长度均小于等于该边长,且路径中的边的个数小于等于K.     在判断路径是否存在的时候,使用BFS搜索,因为BFS用于寻找最短(边的个数最少)路径. 实现 #include<stdio.h> #include<string.h

UVALive 3971 Assemble(模拟 + 二分)

UVALive 3971 题意:有b块钱,想要组装一台电脑,给出n个配件的种类,名字,价格,品质因子.若各种类配件各买一个,总价格<=b,求最差品质配件的最大品质因子. 思路: 求最大的最小值一般用二分法. 在(0,maxq)内进行二分,判定q作为最差品质因子是否可行. 大白书原题,比较考验代码功底. code: /* * @author Novicer * language : C++/C */ #include<iostream> #include<sstream> #i

UVALive - 3635 - Pie(二分)

题意:有F + 1(1 <= F <= 10000)个人分N(1 <= N <= 10000)个圆形派,每个人得到的派面积相同,且必须是一整块(不能够两个甚至多个派拼在一起),求每个人最多能得到多大面积的派.(误差最多到0.001) 因为答案是小数类型的,并且N高达10000,故不可暴力枚举. 可以二分枚举最大面积,然后检查是否切出来派的总个数大于等于F + 1. (判相等时不可直接判相等,需要加精度控制) #include<cstdio> #include<cs

bzoj1082: [SCOI2005]栅栏(二分答案搜索判断)

1082: [SCOI2005]栅栏 题目:传送门 题解: 是不是一开始在想DP?本蒟蒻也是qwq,结果很nice的错了ORZ 正解:二分+搜索 我们可以先把两种木材都进行排序,那么如果需要的最大木材比可提供的最大木材还要大的话,那么可以直接舍弃这种需要的木材. 然后就可以进入二分,如果当前可以做贡献的提供木材加起来都没有前mid块需要木材大的话,很明显当前mid不ok 返回判断值再记录答案就好了,注意一些小细节的优化 代码: 1 #include<cstdio> 2 #include<

UVAlive 7366 Brocard(二分+计算几何)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5388 思路:二分Brocard angle设为rad,将两条边(AB,BC)按该角度旋转,求出两条边的交点P,判断CA与CP所成角度ang是否等于该角度,若rad>ang则rad应减小(r=mid),即使得ang变大,否则rad应增大(l=mid),直到两者相

UVALive 3971 Assemble(二分+贪心)

本题思路不难,但是要快速准确的AC有点儿考验代码功力. 看了大白书上的标程,大有所获. 用map和vector的结合给输入分组,这个数据结构的使用非常精美,恰到好处. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include&l

UVALive 6525 Attacking rooks 二分匹配 经典题

题目链接:option=com_onlinejudge&Itemid=8&page=show_problem&problem=4536">点击打开链接 题意: 给定n*n的棋盘, 能够在'.'上摆 象棋中的车(X是墙壁) 使得随意两个车都不能互相攻击到 问:最多能摆多少个车. 思路: 二分匹配 1.若没有X.那么做法就是 X点集为行,Y点集为列,对于图上的每一个点所在的行和列(x,y) 建一条边 x->y 2.有了X,那么对于每一个点所在的上方能接触到的X必须