Graham扫描法解决凸包边界问题
本文最后更新于509 天前,其中的信息可能已经过时,如有错误请发送邮件到1910452164@qq.com

在一个阳光明媚的下午, Mr.Box与 hdu2202 最大三角形 相遇了,经过一番学习和思考,他最终AC了这道题,题面如下:

思路:

  1. 利用graham算法算出所给点集中相连起来可以包围住所有点的子集P,如下图:

2. 暴力枚举子集P中任意三个点对,更新最大三角形面积。

不难看出,本题的关键在于求出子集P,下面介绍Graham扫描法:

1. 找出输入的点坐标中,优先最靠下,次优最靠左的点;

2. 以该点为原点平移坐标系;

3. 利用内置的atan2函数写cmp函数,将点集按照优先与x轴夹角最小,次优与原点最近的原则排序;

atan2函数:atan2(y, x),C++中一种double类型的反正切函数,返回值为弧度,是点(0,0)和(x,y)的连线与X轴正半轴的夹角,其值域为 [-π,π] (当y=0时,可以取到±π),且在第一二象限为正,在第三四象限为负,无特殊头文件

bool cmp(point a, point b)
{
    if (atan2(a.y, a.x) != atan2(b.y, b.x))
        return atan2(a.y, a.x) < atan2(b.y, b.x);
    else return a.x < a.y;
} 
/* 先判断两点与x轴连线的的角度谁更小,相同则返回离原点更近的那个 */

4. 将点集中前两个元素分别入栈;

5. 遍历接下来点集中每个点,设为t,设栈顶元素为p1,栈顶下面一个元素为p0。则如果向量 p0p1 x p1p2 < 0,则将栈顶元素出栈,一直循环至叉积结果为正,再将t入栈;

bool cross_mul(point a, point b, point c) 
{
    int x1 = b.x - a.x, y1 = b.y - a.y;
    int x2 = c.x - a.x, y2 = c.y - a.y;
    return x1 * y2 - x2 * y1 > 0;
} // 返回向量ab叉乘bc是否为正

/* graham核心代码,n为输入点集容量,cnt为栈内元素个数,初始值为0 */
for (int i = 2; i < n; ++i) 
{
    while (i >= 0 && !cross_mul(stack[cnt - 2], stack[cnt - 1], p[i]))
        cnt--;
    stack[cnt++] = p[i];
}

6. 最后栈内的就都是凸包的边界点。

追加一个利用叉乘快速计算三角形面积的公式

S=|(x1*y2+x2*y3+x3*y1-y1*x2-y2*x3-y3*x1)/2|

OVER

最后记录一下最近听的《当爱已成往事》:

“不要问我是否再相逢,
不要管我是否言不由衷。”

评论

  1. DayBreak
    博主
    1 年前
    2024-11-30 18:30:48

    修改一下,第五条“则如果向量 p0p1 x p1p2 < 0”改为“则如果向量 p0p1 x p0p2 < 0”,谢谢 @Mr.Box 的指正

  2. 1 年前
    2024-12-02 9:12:48

    这篇文章十分强大 学到了很多 谢谢作者大大!

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇