2023-01-12 14:06阅读: 92评论: 1推荐: 0

【计算几何】浅谈凸包Andrew算法

前置知识

计算几何基础知识

引文

这样一个问题,

有许多个杆子,需要用绳子围住所有的杆子,然鹅没有很多的绳子,求最短需要多少绳子。

整个图大概是这样的,

正文

我们要如何解决这题呢?不难想出,最优解法应该是这样的,

而这个图中隐藏着解决这道题的奥秘。

特别的这个图被我们称为凸包。

首先我们可以把它分割成两个图,分为上壳与下壳

分析一下,我们可以发现,在上壳中,编号从大到小,都是向右转,下壳相同。

可以推测个结论,在上壳中,如果一个节点需要左转,这次时必定不是最优的,下壳相同,

怎么样才能改成最优的呢?很简单,让他变成向反方向转:将之前的节点一个个删除,直到达到目的为止。

凸包步骤

首先,将节点按 x 第一关键字, y 第二关键字排序,

然后枚举上壳:现将节点 A 与节点 B 加入凸包,并加入 C

尝试连接 E ,然而由于 CAB 的左方向,并不是最短的,所以并不可行,

D 删去凸包中,依次连接 EFI

不可行,将 F 删去;

这样上壳就枚举完了,便开始枚举下壳。

下壳是从编号大向编号小的枚举,

依次加入 IGFD

然而 DGF 的左边,自然并非最优,

删掉 F ,连入 C

发现 CGH 的左边,于是删掉 G ,连入 A 。( B 显然连不了)

然后凸包便成功生成了出来11!

补充

还有最后一个问题,我们该如何判断一个点在直线的方向?

将该节点与直线首尾相接,当这两个直线的叉积大于 0 时,点在左方;

小于 0 时,点在右方;

当其等于 0 时,点与直线共线。

代码

inline int Andrew(Point *p, int n, Point *Poly) { // 求凸包
  int used[N] = {0};                              // 标记每个数字是否使用过
  sort(p + 1, p + n + 1, [](Point a, Point b) {   // 排序节点
    return a.x < b.x || (a.x == b.x && a.y < b.y);
  });
  int cnt = 3;
  Poly[1] = p[1], Poly[2] = p[2];                 // 初始时加入1号和2号节点
  for (int i = 3; i <= n; ++i) {
    if (cnt > 1 && Cross(Poly[cnt] - Poly[cnt - 1], Poly[i] - Poly[cnt] <= 0)) { // 判断是否在左边
      -- cnt;                                                                    // 删除此节点
      used[Poly[cnt + 1]] = 0;
    }
    used[i] = 1;                                 // 标记节点
    Poly[++ cnt] = p[i];                         // 加入凸包
  }
  int k = cnt;                                   // 上壳的起点
  for (int i = n; i >= 1; --i) {
    if (used[i]) {                               // 已经加入凸包
      continue;
    }
    while (cnt > k && Cross(Poly[cnt] - Poly[cnt - 1], Poly[i] - Poly[cnt]) <= 0)) {
      -- cnt;
      used[Poly[cnt + 1]] = 0;
    }
    used[i] = 1;
    Poly[++ cnt] = p[i];
  }
  Poly[++ cnt] = 1;                              // 便于计算周长
  return cnt;
}

本文作者:SenGYiの小屋

本文链接:https://www.cnblogs.com/Sengyi/p/17046518.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SenGYi  阅读(92)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.