【算法设计与分析 李春葆】计算几何(二)——求解凸包问题

本文探讨了凸多边形和凹多边形的区别,并介绍了如何计算点集凸包,重点讲解了礼品包裹法和Graham扫描算法。同时,对比了两种求凸包算法的时间复杂度,包括排序在内。最后,提供了Andrew算法求凸包的实例代码,展示了实际应用中如何求解最短围栏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

凸多边形以及凹多边形的区别:

  1. 凸多边形没有凹陷处,但是凹多边形至少有一个凹陷处。
  2. 凸多边形任意两点均在内部,但是凹多边形至少有一对点,他们的连线在多边形外部。
  3. 沿着凸多边形的转向是相同的,而沿着凹多边形的转向有不同的地方,这个地方正是凹点。

点集的凸包

定义:在平面上能包含所有给定点的最小凸多边形叫做凸包。

形象理解:礼品包裹法

性质:是包含所有的点的多边形中周长最小的

礼品包裹法

时间复杂度: O ( n h  ) O(nh) O(nh),n为所有的点,h为凸包上的点。

这种算法只是玩一玩。

思路:找边界的一个点(最左边,如果有多个是相同的,那么就取最下面)

然后过这一个点做射线逆时针旋转,找到第一个碰到的点,这一个点也加入凸包中

这里不太想实现,太low了。

Graham 扫描算法

[USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包(洛谷)

题目描述

农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

输入格式

输入数据的第一行是一个整数。表示农夫约翰想要围住的放牧点的数目 n n n

2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行两个实数,第 ( i + 1 ) (i + 1) (i+1) 行的实数 x i , y i x_i, y_i xi,yi 分别代表第 i i i 个放牧点的横纵坐标。

输出格式

输出输出一行一个四舍五入保留两位小数的实数,代表围栏的长度。

输入

4
4 8
4 12
5 9.3
7 8

输出

12.00

提示

数据规模与约定:

对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105 − 1 0 6 ≤ x i , y i ≤ 1 0 6 -10^6 \leq x_i, y_i \leq 10^6 106xi,yi106。小数点后最多有 2 2 2 位数字。

废话不说,直接上代码:

鉴于原题是毒瘤题,所以除了前两个可以过就行了

#include <bits/stdc++.h>
using namespace std;
#define N 100020

class Point{
    public:
    double x, y;
    Point(){};
    Point(double x1, double y1){
        x = x1;
        y = y1;
    }
    void disp(){
        printf("(%g, %g)", x, y);
    }
};
int n;
Point a[N];
Point stac[N];
int top = 0;
Point operator -(const Point &p1, const Point &p2){
    return Point(p1.x - p2.x, p1.y - p2.y);
}

double Det(const Point &p1, const Point &p2){
    return p1.x*p2.y-p1.y*p2.x;
}

int Direction(const Point &p0, const Point &p1, const Point &p2)
{
    double d = Det(p1-p0, p2-p0);
    if(d > 0) return 1;
    else if(d == 0) return 0;
    else return -1;
}
bool cmp(const Point &p1, const Point &p2)
{
    return Direction(a[1], p1, p2) > 0;
}

double Distance(const Point &p1, const Point &p2)
{
    Point t = p1-p2;
    return sqrt(t.x*t.x + t.y*t.y);
}


void solve()
{
    int pos = -1;
    for(int i = 1; i <= n; i++)
    {
        if(pos == -1 || a[i].y < a[pos].y || a[i].y == a[pos].y && a[i].x < a[pos].x)
            pos = i;
    }
    swap(a[1], a[pos]);
    sort(a+2, a+1+n, cmp);
    for(int i = 1; i <= n; i++) a[i].disp();
    stac[++top] = a[1];
    stac[++top] = a[2];
    stac[++top] = a[3];

    for(int i = 4; i <= n; i++)
    {
        while(top >= 2 && ( Direction(stac[top-1], stac[top], a[i]) < 0  ||
                            Direction(stac[top-1], stac[top], a[i]) == 0 && 
                            Distance(stac[top-1], a[i]) > Distance(stac[top-1], stac[top]))
                          )
        {
            top --;
        }
        stac[++top] = a[i];
    }
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        double x, y;
        scanf("%lf%lf",&x, &y);
        a[i] = Point(x, y);
    }
    solve();
    //for(int i = 1; i <= top; i++) stac[i].disp();
    double ans = 0.0;
    for(int i = 1; i <= top - 1; i++)
    {
        ans += Distance(stac[i], stac[i+1]);
    }
    ans += Distance(stac[1], stac[top]);
    printf("%.2lf", ans);
    return 0;
}

这一个算法的时间复杂度是 n l o g n nlogn nlogn(排序的时间)

Andrew 算法求凸包

这一个算法的时间复杂度是 n l o g n nlogn nlogn(瓶颈也在排序的时间)

### 回答1: 《算法设计分析李春葆pdf》是由李春葆所编著的一本关于算法设计分析的参考书籍,该书以系统全面的方式介绍了算法设计分析的相关概念、技巧和方法。 该书第一部分主要介绍了算法问题求解的基础知识,包括算法的基本概念、时间复杂度和空间复杂度等。作者通过具体的例子和细致的讲解,帮助读者理解算法的定义和性质,以及了解如何评估算法的效率。 第部分以常见的算法设计技巧为核心,详细阐述了递归算法、贪心算法、动态规划算法和回溯算法等。这些算法设计技巧在实际问题求解中经常使用,对于提高算法的效率和准确性非常重要。通过学习这些技巧,读者可以了解到不同算法设计背后的思维方式和解题思路,进而在实践中灵活运用。 第三部分主要介绍了图论算法和字符串匹配算法,这些算法在计算机科学领域有着广泛的应用。通过学习这些算法,读者可以掌握图的基本概念、图遍历算法、最短路径算法等,并了解字符串匹配算法的原理和应用。 除了算法设计分析的内容外,该书还提供了大量的习题和实例,方便读者巩固所学知识和提升解题能力。通过解答习题和实践训练,读者可以更好地理解算法设计分析的思想,提高自己的算法水平。 总之,《算法设计分析李春葆pdf》是一本全面系统介绍算法设计分析的优秀参考书籍,适合计算机科学及相关专业的学生和从业者阅读学习。无论是初学者还是有一定算法基础的人士,都能够从中获取到丰富的知识和实践经验,提高自己的算法设计分析能力。 ### 回答2: 《算法设计分析李春葆.pdf》是一本由李春葆编写的算法设计分析的教材。本书总共分为七个章节,内容包括基础知识、排序算法、查找算法、图算法、动态规划、贪心算法和分治算法。 第一章介绍了算法设计分析的基础知识,包括算法的定义、性质和分类方法,以及算法分析的基本原理和方法。这些基础知识为后面的章节打下了坚实的基础。 第章介绍了常见的排序算法,包括插入排序、选择排序、冒泡排序、快速排序、归并排序等。每种排序算法都给出了详细的算法步骤和时间复杂度分析,帮助读者理解算法的原理和性能。 第三章讲解了查找算法,包括线性查找、分查找、哈希查找等。每种查找算法都给出了具体的实现步骤和时间复杂度分析,帮助读者掌握不同查找算法的优缺点和适用场景。 第四章介绍了图算法,包括图的遍历算法、最短路径算法、最小生成树算法和拓扑排序算法等。每种图算法都给出了解题思路和详细的算法步骤,帮助读者理解和解决图相关问题。 第五章介绍了动态规划算法,这是一种处理具有重叠子问题和最优子结构性质的问题的有效方法。本章详细介绍了动态规划的原理和方法,并给出了具体的应用例子,帮助读者掌握动态规划的解题思路。 第六章介绍了贪心算法,这是一种通过每一步的局部最优选择来达到全局最优的方法。本章给出了贪心算法的定义和基本思想,并通过具体的案例和算法实现来讲解贪心算法的应用。 第七章介绍了分治算法,这是一种将问题分解为多个子问题,再将子问题的解合并得到原问题解的方法。本章详细讲解了分治算法的基本思想和应用,通过具体的案例和算法实现帮助读者理解分治算法的原理。 通过阅读《算法设计分析李春葆.pdf》,读者可以全面了解算法设计分析的基础知识和常用算法的原理和应用。这本教材用简明易懂的语言讲解了复杂的算法原理,并通过详细的算法步骤和示例帮助读者掌握算法设计分析方法。无论是计算机专业的学生还是从事算法研究和开发的工程师,都可以从这本教材中受益。 ### 回答3: 《算法设计分析》是由李春葆编写的一本介绍算法设计分析的教材。该教材主要从理论和实践两个方面来解释算法设计分析方法。 首先,该教材从理论层面介绍了常见的算法设计方法,如贪心算法、动态规划、分治算法等。这些方法能够帮助读者理解和掌握算法的基本原理和思想。同时,该教材还介绍了各种算法的时间复杂度和空间复杂度的分析方法,使得读者能够评估和比较不同算法的效率和性能。 其次,该教材注重实践环节,通过大量的示例和练习题,帮助读者加深对算法设计分析的理解应用。在实践环节中,读者不仅能够了解常见算法的实现过程,还能学会如何调试和优化算法,提高算法的效率和准确性。 此外,该教材还涵盖了一些高级算法设计分析,如图算法、字符串算法等。这些高级算法在实际应用中具有重要作用,通过学习这些算法,读者可以了解到更多领域的算法设计分析方法。 总的来说,李春葆编写的《算法设计分析》是一本内容丰富、理论联系实际的教材。无论是对于算法初学者还是对于有一定算法基础的人来说都是一本很好的参考书,可以帮助读者深入理解算法设计分析的思想和方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值