洛谷题目:P2742 [USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包 题解 (本题较难)

news2025/1/22 14:59:59
题目传送门:P2742 [USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

另:由于一些文章的疏忽,导致一些错别字,代码错误,公式错误导致大家的理解和误导,到后期作者会进行更改,感谢大家!!!(如果有发现勘误请大家联系作者)

前言:

        本题涉及到计算几何、分治,凸包,这道题相对来说比较的难(对我来说一点都不难),可可能对那些计算几何、凸包的初学者理解起来较为抽象,刚好下一期的文章就是写关于计算机几何,凸包的知识分析与理解,帮助大家。

题目来自:

        题目来自USACO是美国计算机奥林匹克竞赛英文名:Wntied States of America Computing 

Olympiad的简称   这道题在洛谷里并没有却出明确的难度,作者自己评了一下,可以给到银级的难度。

1、题目分析:

        本题的目标是计算能够围住给定的 n 个放牧点的最短围栏长度。从几何角度来看,这个最短的围栏实际上就是这些点的凸包的周长。凸包是包含所有给定点的最小凸多边形,它的特点是凸包上的点使得多边形的内部角度都小于或等于 180 度。

2、Graham扫描算法:

        1、找到最下方的点:

                首先,我们需要找到所有点中 y 坐标最小的点,如果有多个点 y 坐标相同时,则选择其中 x 坐标最小的点。这个点将作为凸包构建的起始点,因为它一定是凸包上的点。

                在代码视线中,我们使用 sort 函数和 compare 函数来实现这一个目的。 compare 函数会将点集按照 y 坐标排序,如果 y 坐标相同,则按照 x 坐标排序这样第一个点就是我们要找的最下方的点。

        2、对其余点进行极角排序:

                对于除最下方点外的其余点,我们将它们按照相对于最下方点的极角进行排序。极角排序可以使用叉积来实现。叉积计算公式:

                        \overrightarrow{OA} \times \overrightarrow{OB}=(A_{x}-O_{x})*(B_{y}-O_{y})-(A_{y}-O_{y})*(B_{x}-O_{x})

                对于三个点 O、 A 和 B,如果叉积 cp (o,a,b)大于0,则B在OA的逆时针方向;如果等于0,则O、A、B共线;如果小于0,则B在OA的顺时针的方向。

                在 cl 函数中,先将所有点按照极角排序,排序依据是 cp 函数。

        3、构建凸包:

                我们使用一个栈(用vector<Point>模拟)来存储凸包上的点。

                首先我们将最下方的点和排序后的第二个点加入栈中。

                然后遍历上下的点,对于每个新点,检查它是否会使栈顶的点和栈顶前一个点构成的边向左转,即叉积大于0。

                如果不是向左转(叉积小于等于 0),则将栈顶元素弹出,直到新点使栈顶元素和栈顶前一个元素构成的边向左转或栈中元素数量小于 2。然后将新点加入栈中。这一过程会构建出凸包的下部分。

                为了构建上部分的凸包,我们从倒数第二个点开始,执行相同的操作,将点加入栈中,直到遍历完所有点。

                最后需要将最后一个重复添加的点从栈中弹出,因为在构建上凸包时会重复添加起始点。

        4、计算凸包周长:

                对于存储在 h 中的凸包上的点,使用 distance 函数计算相邻点之间的距离。

                distance 函数函数使用欧几里得距离公式:

                \sqrt{(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}} 来计算两点之间的距离。

                将所有相邻点的距离相加,最后加上最后一个点和第一个点之间的距离,就得到了凸包的周长,也就是最短围栏的长度。

3、输入、出处理:

        1、输入:

                首先从标准的输入读取一个整数 n ,表示点的数量。

                然后读取 n 行,每行包含一个点的 x 和 y 坐标。

        2、输出:

                计算出最短围栏长度(凸包周长)后,将结果保留并2位小数输出。

5、示例:

        假设我们输入为:

4
4 8
4 12
5 9.3
7 8
  1. 首先找到最下方的点,经过排序后是 (4, 8)
  2. 对其他点进行极角排序。
  3. 构建凸包,通过 cl 函数,得到凸包上的点序列。
  4. 使用 perimeter 函数计算凸包周长,最终将结果输出,保留两位小数。

6、代码:

#include <bits/stdc++.h>
using namespace std;
struct Point {
    double x;
    double y;
};
double cp(const Point& O, const Point& A, const Point& B) {
    return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
}
bool c(const Point& p1, const Point& p2) {
    if (p1.y == p2.y) {
        return p1.x < p2.x;
    }
    return p1.y < p2.y;
}vector<Point> cl(vector<Point>& points) {
    int n = points.size();
    if (n <= 1) {
        return points;
    }
    sort(points.begin(), points.end(), c);
    vector<Point> hull;
    for (int i = 0; i < n; ++i) {
        while (hull.size() >= 2 && cp(hull[hull.size() - 2], hull.back(), points[i]) <= 0) {
            hull.pop_back();
        }
        hull.push_back(points[i]);
    }
    int lll = hull.size();
    for (int i = n - 2; i >= 0; --i) {
        while (hull.size() > lll && cp(hull[hull.size() - 2], hull.back(), points[i]) <= 0) {
            hull.pop_back();
        }
        hull.push_back(points[i]);
    }
    hull.pop_back(); 
    return hull;
}
double d(const Point& p1, const Point& p2) {
    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;
    return sqrt(dx * dx + dy * dy);
}
double pi(const vector<Point>& hull) {
    double p = 0;
    int n = hull.size();
    for (int i = 0; i < n - 1; ++i) {
        p += d(hull[i], hull[i + 1]);
    }
    p += d(hull[n - 1], hull[0]);
    return p;
}
int main() {
    int n;
    cin >> n;
    vector<Point> points(n);
    for (int i = 0; i < n; ++i) {
        cin >> points[i].x >> points[i].y;
    }
    vector<Point> h = cl(points);
    double l = pi(h);
    cout << fixed << setprecision(2) << l << endl;
    return 0;
}

总的来说其实这道题一点都不难的,虽然计算几何和凸包理解起来比较抽象,但是只要能理解,无论有多难,都是能啃下来的

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

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

相关文章

多线程之旅:线程安全问题

之前说到了多线程的创建和一些属性等等&#xff0c;接下来&#xff0c;就来讲讲多线程安全问题。 小编引入这段代码讲解下&#xff1a; public class Demo13 {public static int count0;public static void main(String[] args) throws InterruptedException {Thread t1new…

html学习笔记(3)

一、文本格式标签 效果标签&#xff08;旧版&#xff09;标签&#xff08;语义化&#xff0c;强调&#xff09;加粗<b><strong>倾斜<i><em>下划线<u><ins>删除线<s><del> 前面的标签 b 、 i 、 u 、 s 就仅仅是实现加粗、倾…

Postgresql源码(141)JIT系列分析汇总

JIT的东西比较零散&#xff0c;本篇对之前的一些列分析做个汇总、整理。 涉及&#xff1a; 《Postgresql源码&#xff08;113&#xff09;表达式JIT计算简单分析》 《Postgresql源码&#xff08;127&#xff09;投影ExecProject的表达式执行分析》 《Postgresql源码&#xff08…

Maven多环境打包方法配置

简单记录一下SpringBoot多环境打包配置方法&#xff0c;分部署环境和是否包含lib依赖包两个维度 目录 一、需求说明二、目录结构三、配置方案四、验证示例 一、需求说明 基于Spring Boot框架的项目分开发&#xff0c;测试&#xff0c;生产等编译部署环境&#xff08;每一个环境…

SDL2基本使用

前言 在这里记录SDL的环境基本搭建和使用&#xff0c;方便回忆。使用该图形库也是为了方便在没有单片机和显示模块的使用&#xff0c;也能对简单验证些关于图形构建或界面管理的猜想和测试&#xff0c;所以下述不会探讨过于深入的东西。当然&#xff0c;也可以通过SDL官网查看介…

【Linux系统编程】—— 从零开始实现一个简单的自定义Shell

文章目录 什么是自主shell命令行解释器&#xff1f;实现shell的基础认识全局变量的配置初始化环境变量实现内置命令&#xff08;如 cd 和 echo&#xff09;cd命令&#xff1a;echo命令&#xff1a; 构建命令行提示符获取并解析用户输入的命令执行内置命令与外部命令Shell的主循…

认识BOM

BOM 弹出层 可视窗口尺寸 屏幕宽高 浏览器内核和其操作系统的版本 剪贴板 是否允许使用cookie 语言 是否在线

[c语言日寄]结构体的使用及其拓展

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

Linux系统的第一个进程是什么?

Linux进程的生命周期从创建开始&#xff0c;直至终止&#xff0c;贯穿了一个进程的整个存在过程。我们可以通过系统调用fork()或vfork()来创建一个新的子进程&#xff0c;这标志着一个新进程的诞生。 实际上&#xff0c;Linux系统中的所有进程都是由其父进程创建的。 既然所有…

5. 马科维茨资产组合模型+AI金融智能体(qwen-max)识别政策意图方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…

PostMan最新版本及离线安装指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;PostMan是一款流行的API测试工具&#xff0c;它提供了一个直观的用户界面&#xff0c;方便Web开发者和测试人员进行接口测试。本文将指导你如何安装最新版的PostMan&#xff0c;包括在线安装和离线安装两种方法。…

记录一次k8s起不来的排查过程

我在k8s集群&#xff0c;重启了一个node宿主机&#xff0c;竟然发现kubelet起不来了&#xff01;报错如下 这个报错很模糊&#xff0c;怎么排查呢。这样&#xff0c;开两个界面&#xff0c;一个重启kubelet&#xff0c;一个看系统日志(/var/log/message:centos&#xff0c;/va…

grafana + Prometheus + node_exporter搭建监控大屏

本文介绍生产系统监控大屏的搭建&#xff0c;比较实用也是实际应用比较多的方式&#xff0c;希望能够帮助大家对监控系统有一定的认识。 0、规划 grafana主要是展示和报警&#xff0c;Prometheus用于保存监控数据&#xff0c;node_exporter用于实时采集各个应用服务器的事实状…

2024年博客之星主题创作|从零到一:我的技术成长与创作之路

2024年博客之星主题创作&#xff5c;从零到一&#xff1a;我的技术成长与创作之路 个人简介个人主页个人成就热门专栏 历程回顾初来CSDN&#xff1a;怀揣憧憬&#xff0c;开启创作之旅成长之路&#xff1a;从平凡到榜一的蜕变持续分享&#xff1a;打卡基地与成长复盘四年历程&a…

Golang的网络编程安全

Golang的网络编程安全 一、Golang网络编程的基本概念 作为一种现代化的编程语言&#xff0c;具有优秀的并发特性和网络编程能力。在Golang中&#xff0c;网络编程是非常常见的需求&#xff0c;可以用于开发各种类型的网络应用&#xff0c;比如Web服务、API服务、消息队列等。Go…

【2024年华为OD机试】(C/D卷,200分)- 5G网络建设 (JavaScriptJava PythonC/C++)

一、问题描述 题目描述 现需要在某城市进行5G网络建设&#xff0c;已经选取N个地点设置5G基站&#xff0c;编号固定为1到N。接下来需要各个基站之间使用光纤进行连接以确保基站能互联互通。不同基站之间假设光纤的成本各不相同&#xff0c;且有些节点之间已经存在光纤相连。 …

消息队列篇--原理篇--RabbitMQ和Kafka对比分析

RabbitMQ和Kafka是两种非常流行的消息队列系统&#xff0c;但它们的设计哲学、架构特点和适用场景存在显著差异。对比如下。 1、架构设计 RabbitMQ&#xff1a; 基AMQP协议&#xff1a;RabbitMQ是基于AMQP&#xff08;高级消息队列协议&#xff09;构建的&#xff0c;支持多…

玻璃样式的登录界面

AI越来越火了,我们想要不被淘汰就得主动拥抱。推荐一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站 先看样式: 源码: <div class="wrapper">

Python数据可视化(够用版):懂基础 + 专业的图表抛给Tableau等专业绘图工具

我先说说文章标题中的“够用版”啥意思&#xff0c;为什么这么写。 按照我个人观点&#xff0c;在使用Python进行数据分析时&#xff0c;我们有时候肯定要结合到图表去进行分析&#xff0c;去直观展现数据的规律和特定&#xff0c;那么我们肯定要做一些简单的可视化&#xff0…

物联网网关Web服务器--CGI开发实例BMI计算

本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境&#xff1a;飞腾派开发板&#xff08;国产E2000处理器&#xff09; 软件环境&#xff1a;飞腾派OS&#xff08;Phytium Pi OS&#xff09; 硬件平台参考另一篇博客&#xff1a;国产化ARM平台-飞腾派开发板…