Graham凸包算法简介

摘要:
凸包真是一个神奇的算法。。对于凸包的概念,我理解对于向量AB和向量BC,记住向量AB*向量BC=AB*BC*sin∠ABC,叉积的绝对值实际上是S△ 对于平面上的一些点,我们需要凸包上的所有点,我们可以使用Graham算法的时间复杂度O思想来首先找到左下点,并根据叉积对其他点进行排序。

凸包真是一个神奇的算法。。


概念

  • 凸包,我理解为凸多边形
  • 叉积 对于向量AB和向量BC,记向量AB*向量BC = AB * BC * sin ∠ABC,而叉积的绝对值其实就是S△ABC/2

对于平面上的一些点,我们要求凸包上所有的点,可以使用Graham算法 时间复杂度O(nlogn)


思路

先找到最左下的点,把其他的点按叉积排序。然后维护一个堆栈,每次利用叉积和栈顶比较判断当前枚举到的点是否是凸包上的点,是则弹出栈顶元素
具体算法Click here

  • 周长
    直接所有相邻两点距离相加

  • 面积
    多边形面积直接利用公式,用叉积计算


常熟巨大的丑陋代码

# include <stdio.h>
# include <stdlib.h>
# include <iostream>
# include <string.h>
# include <math.h>
# include <algorithm>
# define RG register
# define IL inline
# define ll long long
# define mem(a, b) memset(a, b, sizeof(a))
# define Min(a, b) (((a) > (b)) ? (b) : (a))
# define Max(a, b) (((a) < (b)) ? (b) : (a))
# define Sqr(a) ((a) * (a))
using namespace std;

const int MAXN = 50001;
int n, top;
struct Point{
    double x, y, len;
} p[MAXN], Point_A, s[MAXN]; //最左下的点 
//求叉积(向量ab,向量ac) 
IL double Cross(Point a, Point b, Point c){
    return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}

IL double Dis(Point a, Point b){
    return sqrt(Sqr(a.x - b.x) + Sqr(a.y - b.y));
}
//极角排序 
IL bool Cmp(Point a, Point b){
    RG double x = Cross(Point_A, a, b);
    if(x > 0) return 1;
    else if(x < 0) return 0;
    a.len = Dis(Point_A, a);
    b.len = Dis(Point_A, b);
    return a.len < b.len;
}
//查找起始点,最左下
IL void Find(){
    RG int temp = 0;
    RG Point a = p[1];
    for(RG int i = 2; i <= n; i++)
        if(p[i].y < a.y || p[i].y == a.y && p[i].x < a.x){
            a = p[i];
            temp = i;
        }
    p[temp] = p[1];
    p[1] = a;
    Point_A = a;//保存起始点
}
//求凸包周长
IL double Length(){
    RG double sum = 0;
    for(RG int i = 1; i <= top; i++)
        sum += Dis(s[i - 1], s[i]);
    return sum;
}
//计算面积
IL double Area(){ 
    RG double sum = 0;
    for(RG int i = 1; i < top - 1; i++)
        sum += Cross(s[0], s[i], s[i + 1]);
    sum = fabs(sum) / 2;
    return sum;
}

IL void Graham(){
    Find();
    sort(p + 2, p + n + 1, Cmp);
    s[0] = p[1]; s[1] = p[2];
    for(RG int i = 3; i <= n; i++){
        while(Cross(s[top - 1], s[top], p[i]) <= 0 && top) top--;
        s[++top] = p[i];
    }
    s[++top] = p[1];
}

int main(){
    while(~scanf("%d", &n) && n){
        top = 1;
        for(RG int i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
        Graham();
        cout << top << " " << length() << " " << Area() << endl;
    }
    return 0;
}

板子题 1.Surround the Trees HDU - 1392 2.Cows POJ - 3348

免责声明:文章转载自《Graham凸包算法简介》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Mac下IntelliJ IDEA快捷键大全打印时报emSize必须大于0下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

postgresql笔记

一旦任何有价值的对象被转移到新所有者,可以使用DROPOWNED命令删除被删除角色所拥有的任何剩余对象。此外,DROPOWNED不会删除整个数据库或表空间。因此,如果角色有任何尚未转移到新所有者的数据库或表空间,则需要手动删除它们。DROPOWNED还将注意到,对于不属于目标角色的对象,删除授予目标角色的任何特权。因为REASSIGNOWNED不会接触这些对...

SqlServer数据库存入decimal类型数据注意事项

对于sqlserver,Decimal可用于存储具有小数点和固定值的值。与浮点和实数不同,十进制用于存储近似值。目的是满足精确数学运算的需要。它是最大和最精确的浮点数字类型。对于十进制类型,请注意必须指定精度;否则,十进制只能存储为整数,就像int一样。例如,十进制是存储长度为18位和小数点后2位的数据。...

Selenium操作示例——鼠标悬停显示二级菜单,再点击二级菜单或下拉列表

这两天在python中玩selenium时,我遇到了一个问题,那就是鼠标移动到页面上的一个按钮或菜单,二级菜单或下拉菜单自动弹出,然后二级菜单或者下拉列表自动点击。...

linux下ifconfig, DNS以及route配置

Linux基本网络配置命令1.ifconfig查看网络接口信息。普通用户使用的ifconfig的完整路径:/sbin/ifconfigifconfig网络接口名称:显示指定接口的详细信息。...

Ubuntu安装时怎样分区

应该首先放置启动分区。并将引导设置为主分区。如果是双系统或多系统安装,通常可以选择逻辑分区。首先,Grub可以在1024柱面后面引导Linux内核;第二,即使有多个Linux安装,/boot也可以完全不共享。此外,非独立/引导分区仅占用根文件夹下约20MB的空间。所以决定是否启动。...

wxparse使用(富文本插件)

优点:唯一已知的可以将HTML转换为小程序识别的插件缺点:转换HTML标签可能需要大量的微信小程序标签和样式配置:步骤1,下载https://github.com/icindy/wxParse第二步:把它放到项目中。我选择页面目录。步骤3:配置wxml以添加:需要时使用:...