套圈·分治

2023-10-26

题目信息

Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.
Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.
你曾经在操场上玩过曲棍球吗?Quoit是一种游戏,在游戏中,平环投出一些玩具,与所有的玩具包围授予。
在赛博地面领域,每个玩具的位置都是固定的,圆环经过精心设计,一次只能环绕一个玩具。另一方面,为了让游戏看起来更有吸引力,戒指的设计半径最大。给定一个场的配置,你应该找到这样一个环的半径。
假设所有的玩具都是平面上的点。如果点与环中心之间的距离严格小于环的半径,则点被环包围。如果两个玩具放在同一点上,圆环的半径被认为是0。

输入

The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.
Output For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.
输入由几个测试用例组成。对于每种情况,第一行包含一个整数 N(2<=N<=100000),即字段中玩具的总数。接下来是N行,每行包含一对(x,y),这是一个玩具的坐标。输入以N=0终止。
输出每个测试用例,在一行中打印Cyberground manager要求的环半径,精确到小数点后2位。

测试样例

4
0 3
3 2
4 0
7 1
0
1.12

解答

#include <iostream>
#include <cmath>
#include <iomanip>
#include <cstdio>
#include <algorithm>

using namespace std;

struct Point
{
    double x;
    double y;
} points[10], temp[10];

struct x_sort
{
    bool operator()(const Point &a, const Point &b) const
    {
        return a.x < b.x;
    }
};

struct y_sort
{
    bool operator()(const Point &a, const Point &b) const
    {
        return a.y < b.y;
    }
};

double Dis(Point a, Point b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

double MinDistance(int start, int end)
{
    //先是寻找递归终点
    if (start + 1 == end)
    {//两个点
        return Dis(points[start], points[end]);
    }
    if (start + 2 == end)
    {//三个点
        double d1 = Dis(points[start], points[start + 1]);
        double d2 = Dis(points[start + 1], points[end]);
        double d3 = Dis(points[start], points[end]);
        return min(d1, min(d2, d3));//返回三个点之间最小的距离
    }

    //分
    int mid_index = (start + end) / 2;//中位数的下标
    double d1 = MinDistance(start, mid_index);//左边点集内的最小距离
    double d2 = MinDistance(mid_index+1, end);//右边点集内的最小距离
    double d = min(d1, d2);
    //比较小的有可能会出现在跨分界的区域内

    //治
    int cnt = 0;//用来记录temp点集中点的个数
    for (int i = start; i <= end; i++)
    { //把x坐标在中界限[-d,d]附近的点收集到temp点集
        if (fabs(points[mid_index].x - points[i].x) <= d)
        {
            temp[cnt++] = points[i];
        }
    }
    sort(temp, temp + cnt, y_sort());//将temp点集按照y坐标排序
    for (int i = 0; i < cnt; i++)
    {//直接枚举,找出收集的点集里的最短距离
        for (int j = i + 1; j < cnt; j++)
        {
            if (temp[j].y - temp[i].y >= d)
            {//没有必要再找了,只会越来越大
                break;
            }
            d = min(d, Dis(temp[i], temp[j]));//更新最小值
        }
    }
    return d;
}

int main()
{
    freopen("E://test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int N;
    while (true)
    {
        cin >> N;
        if (N == 0)
        {
            break;
        }
        for (int i = 0; i < N; i++)
        {
            cin >> points[i].x >> points[i].y;
        }
        sort(points, points + N, x_sort());

        double minDistance = MinDistance(0, N - 1) / 2;
        cout << fixed << setprecision(2) << minDistance << endl;
    }
    return 0;
}

想法

本题最简单的含义便是给出众多的点集,要找到距离最短的两个点
1、 分
对于最初输入的 n 个点构成的点集S,大致均分成两部分:以所有点的x坐标的中位数mid为界,分为点集S1:x坐标比mid小的点 和 点集S2:x坐标比mid大的点。如下图所示:
在这里插入图片描述
很明显,这里要继续分别向点集S1和S2递归地调用求解。递归的终点:要处理的点集S只有两个点或者三个点,直接计算出最小距离返回。
2、治
对于点集S1已经求得最短距离d1,点集S2已经求得最短距离d2,两者的并集S的最短距离d是多少呢?暂且取 d = min(d1, d2)。分离出temp点集
需要注意到,在分界线两侧,容易出现比 d 更小的答案。我们需要在距离分界线 d 之内枚举各点,是否出现比 d 更小的答案,如果有,则要更新d。于是我们将在距离分界线 d 之内的各点储存在temp点集中,方便接下来的讨论。
在这里插入图片描述
在temp点集中找更小值
1.尽管temp点集已经缩小了范围,一一枚举还是有点浪费时间。那么还有更好的优化,我们将 temp点集 按照 y 坐标排序。
2.然后对两两坐标一一枚举求距离。先确定某一点,然后一一枚举其后的其他点,求两点距离:先判断两点的 y 坐标是否超出d,如果超出,则不必再枚举,因为距离必将大于 d,其没有枚举完的点也是。(排序的作用就体现在此,方便枚举与舍弃)
下面这张图可以加深对枚举与舍弃的理解:
在这里插入图片描述
考虑将所有点分别存入两个点集(结构体数组)X、Y内,第一个点集按照x坐标排序好,第二个点集按照y坐标排序好,并且Y点集中的每个点(用结构体/class实现)除了x、y坐标还要储存有对应该点在X点集的下标。一直在X点集内进行分治处理。
注意:在每个递归层中,X、Y、Temp 在 [l, r]内元素是一样的,就是排列方式不同(点集Y与点集Temp需要分离(递归前)和归并(递归后)操作)。然后在选出 “temp点集” 时能直接从Y点集中选取,并存入Temp点集中。因为传入的Y本身有序,就省去了对Y点集排序的时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

套圈·分治 的相关文章

  • 数据挖掘的种种-节课准备

    数据挖掘 Data Mining DM 又称数据库中的知识发现 Knowledge Discover in Database KDD 数据挖掘概述 数据挖掘 Data Mining DM 又称数据库中的知识发现 Knowledge Disc
  • C# InvokeRequired和Invoke

    一 简介 WinForm 关于InvokeRequired与Invoke Jlins的博客 CSDN博客 invokerequired c 是禁止夸线程直接访问控件 InvokeRequired是为了解决这个问题而产生的 当一个控件的Inv

随机推荐

  • cpu与gpu实现矩阵相乘对比

    1 完成矩阵相乘的并行程序的实现 要求 实现2个矩阵 1024 1024 的相乘 数据类型设置为float 1 使用CPU计算 include
  • 开源的一些基础介绍

    国内 淘宝 百度 南航 网易等 国外 新浪 搜狐 facebook ebay google等 成功后的企业也在不断为开源添加新能量 如 taobao和google等 因为他们不但被开源的魅力深深吸引住同时也愿意通过开源提升自我 现在更多的企
  • Wrappers.<实体>lambdaQuery的使用

    文章目录 MP 配置 Service CURD接口 Mapper CURD接口 insert delete update select 条件构造器 LambdaUpdateWrapper Wrappers lt 实体 gt lambdaUp
  • 机器人教育是一种科学的探究方式

    创新是推动经济社会发展的核心驱动力 当前 我国已经深刻认识到世界新科技革命带来的机遇和挑战 以高度的历史责任感 强烈的忧患意识和宽广的世界眼光 把创新作为推动经济社会发展的驱动力量 机器人技术的进步将会对科学与技术的发展产生重要影响 只有开
  • 算法(C)(两数之和)

    题目 两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 数组中同一个元素在答案里不
  • JSON使用的一些总结

    http sx666 blogspot com 2007 11 json html JSON JavaScript Object Notation 是一种轻量级的数据交换格式 它采用完全独立于语言的文本格式 可以用来在客户端和服务器端传输数
  • innerText和innerHTML区别

    innerText和innerHTML区别 尽管DOM带来了动态修改文档的能力 但对开发人员来说 这还不够 IE4 0为所有的元素引入了两个特性 以更方便的进行文档操作 这两个特性是innerText和innerHTML 其中innerTe
  • Oracle:重复数据去重,只取其中一条(最新时间/其他字段排序规则)数据

    一 问题 一个会话id代表一个聊天室 返回该聊天室最新的一条数据显示在会话列表 二 解决思路 使用row number over 分组排序功能 来解决该问题 1 语法格式 row number over partition by 分组列 o
  • TMOD、SCON、PCON寄存器的配置

    TMOD控制寄存器 TMOD是定时器 计数器模式控制寄存器 它是一个逐位定义的8为寄存器 但只能使用字节寻址 其各位是 由上图我们就可以看出 这个寄存器控制了两个定时器 计数器 寄存器的高四位控制定时器1 低四位控制定时器0 GATE 门控
  • 数据分析毕业设计 二手房数据爬取与分析可视化系统 -python

    1 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求 为了大家能够顺利以及最少的精力通过毕设 学长分享优质毕业设计项
  • Air700E开发板

    文章目录 基础资料 概述 主要功能 外设分布 PinOut 管脚定义 管脚功能说明 固件升级 正常开机模式 下载模式 IO 电平选择 基础资料 Air700E文档中心 概述 EVB Air700E 开发板是合宙通信推出的基于 Air700E
  • 去除VsCode代码前面的小点点

    去除VsCode代码前面的小点点 去除图片中的点 步骤 File gt Preferences gt Setting 搜索RenderWhitespace 将Text Editor下的Editor Render Whitespace改为no
  • peewee-async使用描述

    1 peewee async是一个为peewee ORM 提供由asyncio支持的异步io库 在单独使用peewee连接池连接时 同时使用到了async和await协程 这样操作会阻塞整个进程 因为tornado是单进程 必须数据库也使用
  • 数据库的简介与类型 #CSDN博文精选# #IT技术# #数据库#

    大家好 小C将继续与你们见面 带来精选的CSDN博文 又到周一啦 上周的系统化学习专栏已经结束 我们总共一起学习了20篇文章 这周将开启全新专栏 放假不停学 全栈工程师养成记 在这里 你将收获 将系统化学习理论运用于实践 系统学习IT技术
  • 高通 AR Unity 虚拟按钮

    1 虚拟按钮是图像上的目标 用户可以在现实世界中触摸 以触发一个动作的 热点 现有的图像目标的一个实例的VirtualButton预制拖动到场景中添加虚拟按键 平移和缩放按钮 以匹配所需的位置 并给它一个名字 虚拟的按钮添加这样写入到con
  • 计算机视觉概述

    关注公众号 CV算法恩仇录 本文介绍了计算机视觉的主要任务及应用 全文大约 3500 字 阅读时间 10 分钟 人们或许没有意识到自己的视觉系统是如此的强大 婴儿在出生几个小时后能识别出母亲的容貌 在大雾的天气 学生看见朦胧的身体形态 能辨
  • v-viewer 插件图片点击放大预览的几种使用方法

    官网git地址 https github com mirari v viewer 最终效果如下 ps 按钮样式都是可以根据自己需求调整的 第一种使用方法 支持UMD用法 建议把v viewer相关的js和css文件下载到本地引用 可以到上面
  • set容器、map容器

    set multiset 容器 set基本概念 简介 所有元素都会在插入时自动被排序 本质 set multiset属于关联式容器 底层结构是用二叉树实现 set和multiset区别 set不允许容器中有重复的元素 multiset允许容
  • elk笔记23--定期清理索引

    elk笔记23 定期清理索引 1 介绍 2 方案 代码 2 1 方案介绍 2 2 代码 2 3 测试 3 注意事项 4 说明 1 介绍 在生产环境中 如果日志量过大 就会导致集群持续产生很多索引 占用很多存储空间 因此需要定期清理索引 确保
  • 套圈·分治

    套圈 题目信息 输入 测试样例 解答 想法 题目信息 Have you ever played quoit in a playground Quoit is a game in which flat rings are pitched at