首页 > 其他分享 >凸包

凸包

时间:2024-01-29 22:14:00浏览次数:21  
标签:return point double top Point 凸包

1. Luogu P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包

上面是板子题

Andrew 算法

  1. 对所有点按坐标 x 为第一关键字、 y 为第二关键字排序。第1、第n两个点一定在凸包上。
  2. 顺序枚举所有点,求下凸包。用维护当前在凸包上的点:新点入栈前,总要判断该弹出哪些旧点。只要新点处在由栈顶两点构成的有向直线的右侧或共线,就弹出旧点。不能弹出时,新点入栈。
  3. 逆序枚举所有点,求上凸包。用维护同上。

注意:每个点入栈两次,出栈不超过两次,所以总次数不超过 。

注意:最后封口时,栈底和栈顶存的都是第一个点。

时间:O(nlogn)

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 using namespace std;
 6 
 7 const int N=100010;
 8 struct Point{double x,y;} p[N],s[N];
 9 int n,top;
10 
11 double cross(Point a,Point b,Point c){ //叉积
12   return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
13 }
14 double dis(Point a,Point b){ //距离
15   return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
16 }
17 bool cmp(Point a, Point b){ //比较
18   return a.x!=b.x ? a.x<b.x : a.y<b.y;
19 }
20 double Andrew(){
21   sort(p+1,p+n+1,cmp); //排序
22   for(int i=1; i<=n; i++){ //下凸包
23     while(top>1&&cross(s[top-1],s[top],p[i])<=0)top--;
24     s[++top]=p[i];
25   }
26   int t=top;
27   for(int i=n-1; i>=1; i--){ //上凸包
28     while(top>t&&cross(s[top-1],s[top],p[i])<=0)top--;
29     s[++top]=p[i];
30   }
31   double res=0; //周长
32   for(int i=1; i<top; i++) res+=dis(s[i],s[i+1]);
33   return res;
34 }
35 int main(){
36   scanf("%d",&n);
37   for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
38   printf("%.2lf\n", Andrew());
39   return 0;
40 }

 

2. Luogu P3829 [SHOI2012]信用卡凸包

思路:圆弧之和=圆的周长

   直边之和=所有圆心构成的凸包的周长

时间:O(nlogn)

 1 #include <bits/stdc++.h>  //
 2 using namespace std;
 3 #define endl '\n'
 4 int _,k, m;
 5 
 6 const double pi = acos(-1);
 7 
 8 
 9 typedef pair<double, double> point;
10 point p[N], s[N];
11 int n, top, cnt;
12 
13 point operator-(point a,point b){ //向量-
14   return point(a.x-b.x,a.y-b.y);
15 }
16 
17 double dis(point a, point b) {  //距离
18   return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
19 }
20 
21 double cross(point a, point b, point c) {  //叉积
22   return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
23 }
24 
25 //逆转角
26 point rotate(point a, double b) {  //将某个向量逆时针旋转b°
27   return point(a.x * cos(b) - a.y * sin(b), a.x * sin(b) + a.y * cos(b));
28 }
29 
30 bool cmp(point a, point b) { return a.x != b.x ? a.x < b.x : a.y < b.y; }
31 
32 double Andrew() {
33   sort(p + 1, p + 1 + n);
34   for (int i = 1; i <= n; i++) {  //下凸包
35     //在栈顶和顶下一个元素构成的有向线段的右侧则入栈,左侧弹出上一个入栈的点
36     while (top > 1 && cross(s[top - 1], s[top], p[i]) <= 0) top--;
37     s[++top] = p[i];
38   }
39   int t = top;                        //中间变量存top
40   for (int i = n - 1; i >= 1; i--) {  //上凸包
41     while (top > t && cross(s[top - 1], s[top], p[i]) <= 0) top--;
42     s[++top] = p[i];
43   }
44   double ans = 0;
45   for (int i = 1; i < top; i++) ans += dis(s[i], s[i + 1]);
46   return ans;
47 }
48 
49 void solve() {
50   cin >> n;
51   double a, b, r;
52   cin >> a >> b >> r;
53   a = a / 2 - r, b = b / 2 - r;  //圆心到中心的边距
54   int dx[] = {1, 1, -1, -1}, dy[] = {1, -1, -1, 1};
55   while (n--) {
56     double x, y, z;
57     cin >> x >> y >> z;
58     for (int i = 0; i < 4; i++) {
59       point t = rotate({dx[i] * b, dy[i] * a}, z);  //四个圆心旋转
60       p[++cnt] = {x + t.x, y + t.y};                //中间圆心平移
61     }
62   }
63   n = cnt;  //圆心个数
64   printf("%.2lf\n", Andrew() + 2 * pi * r);
65 }
66 
67 int main() {
68   // cin >> _;
69   _ = 1;
70   while (_--) {
71     solve();
72   }
73   return 0;
74 }

练习:

POJ1113 Wall

思路:答案就是凸包周长 + 半径为 L 的圆的周长

Luogu P4724 【模板】三维凸包

Luogu P2287 [HNOI2004]最佳包裹

标签:return,point,double,top,Point,凸包
From: https://www.cnblogs.com/rw666/p/17995466

相关文章

  • 二维凸包复习笔记
    Graham扫描法向量的叉乘:平行四边形面积,顺负逆正,x1y2-x2y11.确定1个凸包上的点:纵坐标最小(纵坐标相同时横坐标最小)的点2.极角排序3.单调栈维护凸包点击查看代码//二维凸包#include<bits/stdc++.h>usingnamespacestd;structt1{ doublex,y;}t[100005];ints[100......
  • Ybt 金牌导航 6.1.H. 时空旅行 / P5416 [CTSC2016] 时空旅行(线段树分治+凸包)
    题意简述初始有版本\(0\),其中仅包含点\(0\),且\(c_0\)给出,\(x_0=0\)。对于第\(i\)个版本,它依赖第\(fr_i\)个版本,而且会在父级版本的基础上进行以下两种操作之一:插入一个新点,并且会给出\(x_i\)和\(c_i\)。删除一个本就存在的点(不为\(0\))给出\(m\)次询问,每次给出......
  • 笔记重修计划一:斜率优化 dp & cdq 分治维护凸包(施工中)
    施工中,但是目前暂停施工。前言刷cdq分治的时候做到了这题,发现自己不是很懂这个东西,跑回去看自己几个月前写的斜率优化dp笔记,当时认为自己弄得很明白了,但现在看来简直就是皮毛,遂弄明白后写下此文,希望自己之后有更多启发时能继续充实这篇文章。若有不妥之处望指出。如果单调......
  • 计算离散点的边界 MATLAB计算多维凸包
    无论是进行回归、拟合还是深度学习,总要将总体数据集划分为训练样本集和测试样本集。然而,一般情况下,测试集位于训练集“所覆盖的范围之内”时(如下图所示,红色星号表示训练样本集所在位置,蓝色圆点表示测试样本集所在位置),测试效果较好,测试结果也更具合理性。但是如何验证测试集是否在......
  • 关于凸包位置关系的判断
    近日恰好和同学谈到多边形之间怎么判断相交关系,便写下这篇博文。由于非凸多边形的不确定性,这里就只谈论凸多边形间位置关系判断的优化。对于分别有\(n\)和\(m\)条边的非凸多边形可以枚举两个多边形的边判断线段是否相交,时间复杂度为\(O(mn)\)。凸多边形(以下简称凸包)也可以......
  • CF70D Professor's task 题解 & 动态凸包板子
    CF70DProfessor'stask题解前言此篇题解用的是\(Andrew\),不想看这种做法的可以绕道。题意动态凸包板子题。维护动态凸包。两种操作,加一个点或查询一个点是否在凸包内。题解首先你得会静态二维凸包。维护二维凸包的方法挺多的,比如什么\(Andrew\)算法,\(Jarvis\)算法还......
  • poj 1113 Wall-----凸包
    凸包问题。先按x坐标排序,x一样的按y排序。取p【0】为开始点,每个点与开始点相连,按x轴正方向,每条线段与x轴的夹角由小到大排序。然后选点求距离。。。本题求凸包的边长+以L为半径的园的周长。//自己的凸包模板#include<stdio.h>#include<string.h>#include<math.h>#include<a......
  • 凸包和凸组合例题
    https://codeforces.com/gym/467720/attachmentsM题网上博客https://blog.csdn.net/weixin_34284188/article/details/94669467我们最终线性组合的点一定会落在凸包内部,我们的答案就是凸包的上,右边界的点,包括端点,也包括凸包边上的点求凸包边上的点的横纵坐标积的最大值,是列......
  • C语言求凸包的算法及实现
    C语言求凸包的算法及实现凸包问题是计算几何中的一个重要问题,它描述了一个点集中最小的凸多边形。在本文中,我们将探讨使用C语言来解决凸包问题的算法及其实现。C语言求凸包的算法及实现凸包算法的关键在于如何确定一个点是否在凸包上。对于一个给定的点集,我们可以选择一点作为......
  • 凸包
    二维凸包定义凸多边形凸多边形是指所有内角大小都在 范围内的 简单多边形。凸包在平面上能包含所有给定点的最小凸多边形叫做凸包。其定义为:对于给定集合X ,所有包含X 的凸集的交集S 被称为X 的 凸包。实际上可以理解为用一个橡皮筋包含住所有给定点的形态。凸包......