AcWing119 袭击

news2024/11/19 9:38:56

目录

  • AcWing119 袭击
    • 题目描述
      • 背景
      • 输入
      • 输出
      • 数据范围
    • 题解
      • 解法
      • 优化
    • 打赏

AcWing119 袭击

题目描述

背景

特工进入据点突袭发电站,已知所有发电站的位置和所有特工的降落位置,求任意特工距离任意核电站的最短距离

输入

  1. 第一行一个整数 T T T,表示有 T T T组数据;
  2. 对于每组数据,第一行一个整数 N N N
  3. 接下来 N N N行,每行两个整数 X , Y X , Y X,Y,代表每个核电站位置的 X , Y X , Y X,Y坐标;
  4. 再接下来 N N N行,每行两个整数 X , Y X , Y X,Y,代表每名特工位置的 X , Y X , Y X,Y坐标;

输出

对于每组数据,输出一个最短距离值,结果保留三位小数且每个输出结果占一行

数据范围

1 ≤ N ≤ 1 e 5 , 0 ≤ X , Y ≤ 1 e 9 1 \le N \le 1e5 , 0 \le X , Y \le 1e9 1N1e5,0X,Y1e9

题解

解法

假设先计算了某个区域内的最小距离,那么任意一对特工和核电站的坐标如果在 x x x y y y方向上超出了这个距离,就不用计算他们之间的距离,由此可以想到分治,先分别算出两个独立点集内的最小距离,再考虑跨越了这两个点集的最小距离,这样就可以得到两个点集合并所得点集内的最小距离
先定义一个结构体数组用于储存位置(无论核电站还是特工的),数组的每个元素包含 x , y x , y x,y坐标,以及一个标签( b o o l bool bool变量)用于表示该位置是核电站的还是特工的
为了方便计算跨越点集的最小距离,先将定义的结构体数组按照 x x x y y y值排序(本文按照 x x x
这样排好序后可以采用二分的方式,每一部分先分别算好其左右两个子部分内的最小距离,比较得到二者中的较小值 a n s ans ans,那么如果想要通过跨越两个部分对 a n s ans ans产生贡献,考虑的点的 x x x值与二分中点的 x x x值之间的差距就必须低于 a n s ans ans
这样筛选出了部分点后,把这些点分为特工和核电站两个部分,分别存入两个数组,对于特工数组中的每一个元素,分别考虑在核电站数组中是否存在元素到它的距离能产生贡献(对于核电站数组中的每一个元素考虑特工数组也可以),这至少需要满足二者 y y y值之间的差距低于 a n s ans ans,为了快速在核电站数组中找到满足条件的元素,可以在二分求解的过程中把按照 x x x值排序的数组再按照 y y y值排序,这样对于特工数组中的每一个元素,只需要在核电站数组中找到满足条件的上下界的下标即可
由此通过一边归并排序一边计算最小值就可以得到最终的答案
代码如下:

#include<cstdio>
#include<cmath>

using namespace std;

#define il inline
#define db double

const int M = 2e5 + 5;
const int inf = 15e8;

typedef struct {
    int x;
    int y;
    bool tag;
}Point;

Point pos[M], t1[M], t2[M];

il void pswap(Point &a, Point &b) {     //交换位置
    a.x^=b.x^=a.x^=b.x;
    a.y^=b.y^=a.y^=b.y;
    a.tag^=b.tag^=a.tag^=b.tag;
}

il db dmin(db a, db b) {
    return a < b ? a : b;
}

il db dis(Point a, Point b) {     //计算两点距离,同tag的点之间距离无限大
    return a.tag == b.tag ? inf : sqrt((db)(a.x - b.x) * (a.x - b.x) + (db)(a.y - b.y) * (a.y - b.y));
}

il void quickSort(int l, int r) {     //按照x值排序
    if(l == r) return ;
    if(l + 1 == r) {
        if(pos[l].x > pos[r].x) pswap(pos[l], pos[r]);
        return ;
    }

    int mid = l + r >> 1, i = l, j = mid + 1, k = 0;
    quickSort(l, mid), quickSort(mid + 1, r);

    while(i <= mid && j <= r) {
        while(i <= mid && pos[i].x <= pos[j].x) t1[++k] = pos[i++];
        while(j <= r && pos[i].x >= pos[j].x) t1[++k] = pos[j++];
    }
    while(i <= mid) t1[++k] = pos[i++];
    while(j <= r) t1[++k] = pos[j++];
    for(i = l, j = 1; j <= k; ++j, ++i) pos[i] = t1[j];
}

il db divideSolve(int l, int r) {     //按照y值排序并计算答案
    if(l == r) return inf;
    if(l + 1 == r) {
        if(pos[l].y > pos[r].y) pswap(pos[l], pos[r]);
        return dis(pos[l], pos[r]);
    }
    
    int mid = l + r >> 1;
    db ans = dmin(divideSolve(l, mid), divideSolve(mid + 1, r));
    int i = l, j = mid + 1;
    int axs = pos[mid].x, k1 = l, k2;
    
    while(i <= mid && j <= r) {
        while(i <= mid && pos[i].y <= pos[j].y) t1[k1++] = pos[i++];
        while(j <= r && pos[i].y >= pos[j].y) t1[k1++] = pos[j++];
    }
    while(i <= mid) t1[k1++] = pos[i++];
    while(j <= r) t1[k1++] = pos[j++];
    k1 = k2 = 0;
    for(i = l; i <= r; ++i) {     //筛选并分类
        pos[i] = t1[i];
        if(t1[i].x > axs - ans && t1[i].x < axs + ans)
            t1[i].tag ? t1[++k1] = t1[i] : t2[++k2] = t1[i];
    }
    if(k1 && k2) {     //找上下界
        t2[k2 + 1].y = inf;
        for(i = 1; i <= k1; ++i) {
            db mxx = dmin(inf, t1[i].y + ans), mnn = t1[i].y - ans;
            if(t2[1].y < mxx) {
                int p1 = 1, p2 = 1;
                for(; t2[p2].y < mxx; ++p2);
                if(t2[1].y <= mnn)
                    for(; t2[p1].y <= mnn; ++p1);
                for(j = p1; j < p2; ++j) ans = dmin(ans, dis(t1[i], t2[j]));
            }
        }
    }
    return ans;
}

int main() {
    int t, n, m;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n), m = n << 1;
        for(int i = 1; i <= n; ++i) scanf("%d%d", &pos[i].x, &pos[i].y), pos[i].tag = 0;
        for(int i = n + 1; i <= m; ++i) scanf("%d%d", &pos[i].x, &pos[i].y), pos[i].tag = 1;
        quickSort(1, m);
        printf("%.3lf\n", divideSolve(1, m));
    }
    return 0;
}

优化

按照 x x x值排序时,对于重复的元素只保留一个
对于存在特工和核电站位置相同的数据,可以在一得到 ! a n s !ans !ans时直接 r e t u r n 0 return 0 return0
对于筛选得到的特工数组中的每一个元素,在核电站数组中找上下界时可以二分查找,并且由于这些元素是排序后筛选的,所以对于特工数组中的每个元素,上下界可以在前一元素的基础上寻找,不用每次都初始化为 0 0 0
代码如下:

#include<cstdio>
#include<cmath>

using namespace std;

#define il inline
#define db double

const int M = 2e5 + 5;
const int inf = 15e8;

typedef struct {
    int x;
    int y;
    bool tag;
}Point;

Point pos[M], t1[M], t2[M];

il bool operator == (Point a, Point b) {
    return a.tag == b.tag && a.x == b.x && a.y == b.y;
}

il bool operator != (Point a, Point b) {
    return a.tag != b.tag || a.x != b.x || a.y != b.y;
}

il int quickRead() {
    int x = 0, f = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-') c = getchar();
    if(c == '-') f = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x * f;
}

il void pswap(Point &a, Point &b) {
    a.x^=b.x^=a.x^=b.x;
    a.y^=b.y^=a.y^=b.y;
    a.tag^=b.tag^=a.tag^=b.tag;
}

il db dmin(db a, db b) {
    return a < b ? a : b;
}

il db dis(Point a, Point b) {
    return a.tag == b.tag ? inf : sqrt((db)(a.x - b.x) * (a.x - b.x) + (db)(a.y - b.y) * (a.y - b.y));
}

il int quickSort(int l, int r) {     //返回值表示去重后从l到多大下标是有效值
    if(l == r) return l;
    if(l + 1 == r) {
        if(pos[l] == pos[r]) return l;
        if(pos[l].x > pos[r].x) pswap(pos[l], pos[r]);
        return r;
    }

    int L = quickSort(l, l + r >> 1), R = quickSort((l + r >> 1) + 1, r);
    int i = l, j = (l + r >> 1) + 1, k = 0;

    while(i <= L && j <= R) {
        while(i <= L && pos[i].x <= pos[j].x) {
            if(pos[i] != t1[k]) t1[++k] = pos[i];
            ++i;
        }
        while(j <= R && pos[i].x >= pos[j].x) {
            if(pos[j] != t1[k]) t1[++k] = pos[j];
            ++j;
        }
    }
    while(i <= L) {
        if(pos[i] != t1[k]) t1[++k] = pos[i];
        ++i;
    }
    while(j <= R) {
        if(pos[j] != t1[k]) t1[++k] = pos[j];
        ++j;
    }
    for(i = l, j = 1; j <= k; ++j, ++i) pos[i] = t1[j];
    return l + k - 1;
}

il db divideSolve(int l, int r) {
    if(l == r) return inf;
    if(l + 1 == r) {
        if(pos[l].y > pos[r].y) pswap(pos[l], pos[r]);
        return dis(pos[l], pos[r]);
    }
    
    int mid = l + r >> 1;
    db ans = dmin(divideSolve(l, mid), divideSolve(mid + 1, r));
    if(!ans) return 0;     //得到0立马返回
    int i = l, j = mid + 1;
    int axs = pos[mid].x, k1 = l, k2;
    
    while(i <= mid && j <= r) {
        while(i <= mid && pos[i].y <= pos[j].y) t1[k1++] = pos[i++];
        while(j <= r && pos[i].y >= pos[j].y) t1[k1++] = pos[j++];
    }
    while(i <= mid) t1[k1++] = pos[i++];
    while(j <= r) t1[k1++] = pos[j++];
    k1 = k2 = 0;
    for(i = l; i <= r; ++i) {
        pos[i] = t1[i];
        if(t1[i].x > axs - ans && t1[i].x < axs + ans)
            t1[i].tag ? t1[++k1] = t1[i] : t2[++k2] = t1[i];
    }
    if(k1 && k2) {
        int p1 = 0, p2 = 0;     //共用p1,p2
        t2[k2 + 1].y = inf;
        for(i = 1; i <= k1; ++i) {
            db mxx = dmin(inf, t1[i].y + ans), mnn = t1[i].y - ans;
            if(t2[p2 + 1].y < mxx) {     //判断是否更新p2
                for(j = k2 - p2; j != 1; ++j >>= 1)     //注意k2-p2,“j!=1”防止死循环,“++j >>= 1”保证可以得到所有数
                    if(t2[p2 + j].y < mxx) 
                        if(t2[(p2 += j) + 1].y >= mxx) break;     //下一项超了直接退出
                if(t2[p2 + 1].y < mxx) ++p2;     //对j==1的特判,保证可以得到所有数
            }
            if(t2[p1 + 1].y <= mnn) {     //判断是否更新p1
                for(j = p2 - p1; j != 1; ++j >>= 1)     //注意p2-p1
                    if(t2[p1 + j].y <= mnn) 
                        if(t2[(p1 += j) + 1].y > mnn) break;
                if(t2[p1 + 1].y <= mnn) ++p1;
            }
            for(j = p1 + 1; j <= p2; ++j) ans = dmin(ans, dis(t1[i], t2[j]));     //注意p1+1
        }
    }
    return ans;
}

int main() {
    int t, n, m;
    t1[0].x = -1, t2[0].y = -inf;     //“t1[0].x = -1”用于去重,“t2[0].y = -inf”用于求下界的二分查找
    t = quickRead();
    while(t--) {
        n = quickRead(), m = n << 1;
        for(int i = 1; i <= n; ++i) pos[i] = {quickRead(), quickRead(), 0};
        for(int i = n + 1; i <= m; ++i) pos[i] = {quickRead(), quickRead(), 1};
        printf("%.3lf\n", divideSolve(1, quickSort(1, m)));
    }
    return 0;
}

打赏

制作不易,若有帮助,欢迎打赏!
赞赏码
支付宝付款码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2132718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot实现SpringMvc上传下载功能实现

SpringMvc上传下载功能实现 1.创建新的项目 1&#xff09;项目信息填写 Spring Initializr (单击选中)Name(填写项目名字)Language&#xff08;选择开发语言&#xff09;Type&#xff08;选择工具Maven&#xff09;Group&#xff08;&#xff09;JDK&#xff08;jdk选择17 &…

深度学习——D1(环境配置)

课程内容 W-H-W 资源 AI地图 物体检测和分割 样式迁移 人脸合成 文字生成图片 预测与训练 本地安装

【IPV6从入门到起飞】5-2 IPV6+Home Assistant(ESP32+MQTT+DHT11+BH1750)传感器采集上传监测

IPV6Home Assistant[ESP32MQTTDHT11BH1750]传感器采集上传监测 1 背景2 实现效果3 Home Assistant配置3-1 MQTT配置3-2 yaml 配置3-3 加载配置 4 ESP32搭建4-1 开发环境4-2 工程代码 5 实现效果 1 背景 在上一小节【IPV6从入门到起飞】5-1 IPV6Home Assistant(搭建基本环境)我…

luogu基础课题单 入门 上

【深基2.例5】苹果采购 题目描述 现在需要采购一些苹果&#xff0c;每名同学都可以分到固定数量的苹果&#xff0c;并且已经知道了同学的数量&#xff0c;请问需要采购多少个苹果&#xff1f; 输入格式 输入两个不超过 1 0 9 10^9 109 正整数&#xff0c;分别表示每人分到…

chapter1-项目搭建

文章目录 序章1. 项目开发基础概念1.1 企业开发中常见的web项目类型1.2 企业项目开发流程1.3 立项申请阶段 2. 需求分析2.1 首页2.2 登录注册2.3 课程列表2.4 课程详情2.5 购物车2.6 商品结算2.7 购买成功2.8 个人中心2.9 我的课程及课程学习 3. 环境搭建3.1 创建虚拟环境3.2 相…

2024.9.13 Python与图像处理新国大EE5731课程大作业,索贝尔算子计算边缘,高斯核模糊边缘,Haar小波计算边缘

1.编写一个图像二维卷积程序。它应该能够处理任何灰度输入图像&#xff0c;并使用以下内核进行操作&#xff1a; %matplotlib inline import numpy as np import matplotlib.pyplot as plt from scipy import linalg import random as rm import math import cv2# import and …

基于云端的SIEM解决方案

最近的一项市场研究爆出了一组惊人的数字&#xff0c;在2024年&#xff0c;网络攻击增加了600%&#xff01;更加令人担忧的是&#xff0c;这恐怕只是冰山一角。世界各地的组织都已经认识到了这一威胁&#xff0c;并正在采取多重措施来抵御来自线下和远程混合式办公模式带来的网…

SpringBoot项目获取统一前缀配置以及获取非确定名称配置

SpringBoot项目获取统一前缀配置以及获取非确定名称配置 在SpringBoot项目中&#xff0c;我们经常看到统一前缀的配置&#xff0c;我们该怎么统一获取 my.config.a.namexiaoming my.config.a.age18 my.config.a.addressguangdong my.config.b.namexiaomli my.config.b.age20 my…

【Unity】手写图片轮播

最近项目空闲&#xff0c;回顾了一下之前写的杂七杂八的软件&#xff0c;比较多&#xff0c;而且比较杂乱&#xff0c;代码能看明白&#xff0c;但是非常不科学&#xff0c;不符合逻辑&#xff0c;然后我就有点无奈&#xff0c;虽说是做了很多年的老程序的&#xff0c;但是遇到…

小目标检测顶会新思路!最新成果刷爆遥感SOTA,参数小了18倍

遥感领域的小目标检测一直是个具有挑战性和趣味性的研究方向&#xff0c;同时也是顶会顶刊的常客。但不得不说&#xff0c;今年关于遥感小目标检测的研究热情尤其高涨&#xff0c;已经出现了很多非常优秀的成果。 比如SuperYOLO方法&#xff0c;通过融合多模态数据并执行高分辨…

数据库安全性控制

‍ 在当今信息化时代&#xff0c;数据库安全性 对于保护数据免受非法访问和损害至关重要。无论是个人数据还是企业机密&#xff0c;数据库安全性控制都能有效地防范潜在的威胁。本文将为你深入浅出地介绍数据库安全性控制的关键方法和机制&#xff0c;帮助你轻松掌握这一重要概…

vulnhub靶机:21 LTR: Scene1

下载 下载地址&#xff1a;https://www.vulnhub.com/entry/21ltr-scene-1,3/ 导入靶机 一直按默认的来&#xff0c;一直下一步 修改网卡 修改靶机和 kali 攻击机网络模式为仅主机模式 把仅主机模式的 IP 修改为 192.168.2.0 信息收集 主机发现 arp-scan -l 靶机 IP 是 192.…

Windows系统下安装Redis

文章目录 1、下载Redis安装包2、解压压缩包3、运行Redis4、Redis连接检测5、Redis相关设置5.1设置环境变量PATH5.2Redis 配置文件修改 1、下载Redis安装包 Windows版本的Redis可以在Github中下载&#xff1a;下载Redis 2、解压压缩包 将下载的压缩包解压到某个目录下&#…

微服务CI/CD实践(五)Jenkins Docker 自动化构建部署Java微服务

微服务CI/CD实践系列&#xff1a; 微服务CI/CD实践&#xff08;一&#xff09;环境准备及虚拟机创建 微服务CI/CD实践&#xff08;二&#xff09;服务器先决准备 微服务CI/CD实践&#xff08;三&#xff09;Jenkins部署及环境配置 微服务CI/CD实践&#xff08;四&#xff09;…

c++20 std::format 格式化说明

在标头<format>定义 ()功能很强大&#xff0c;它把字符串当成一个模板&#xff0c;通过传入的参数进行格式化&#xff0c;并且使用大括号‘{}’作为特殊字符代替‘%’。 1、基本用法 &#xff08;1&#xff09;不带编号&#xff0c;即“{}”&#xff08;2&#xff09;带…

学会使用西门子博途Startdrive中的测量功能

工程师在驱动调试过程中&#xff0c;往往需要对驱动系统的性能进行分析及优化&#xff0c;比如说借助于调试软件中的驱动器测量功能&#xff0c;可以得到驱动系统的阶跃响应、波特图等&#xff0c;以此为依据工程师可以调整速度控制器、电流控制器的相关参数&#xff0c;使驱动…

今天一定要彻底卸载Windows Denfender!攻略给你了

最近有小伙伴吐槽&#xff1a;明明都已经把Windows Defender关了&#xff0c;为啥它还会时不时拦截我下载的文件&#xff1f; 小白就问&#xff1a;明明是谁&#xff1f; 嗯…… 肯定有小伙伴遇到同样的问题&#xff0c;Windows Defender已经关了&#xff0c;但好像并没有完…

利用Xinstall,轻松搭建高效App运营体系

在移动互联网时代&#xff0c;App的推广和运营成为了企业发展的关键环节。然而&#xff0c;随着流量红利的逐渐消失&#xff0c;传统的推广方式已经难以满足企业快速获客的需求。在这个背景下&#xff0c;Xinstall作为一款强大的渠道推广工具&#xff0c;凭借其独特的功能和优势…

【IP协议】IP协议报头结构(上)

IP 协议报头结构 4位版本 实际上只有两个取值 4 > IPv4&#xff08;主流&#xff09;6 > IPv6 IPv2&#xff0c;IPv5 在实际中是没有的&#xff0c;可能是理论上/实验室中存在 4位首部长度 IP 协议报头也是变长的&#xff0c;因为选项个数不确定&#xff0c;所以报头长…

【达梦数据库】mysql 和达梦 tinyint 与 bit 返回值类型差异

测试环境 mysql5.7.44 达梦2024Q2季度版 前言 在mysql 中存在 tinyint&#xff08;1&#xff09;的用法来实现存储0 1 作为boolean的标识列&#xff1b;但是在达梦并不允许使用 tinyint&#xff08;1&#xff09;来定义列&#xff0c;只能使用 tinyint 即 取值范围为&#xff…