寻找凸包.

预备知识:叉积

u = (u1, u2)

v=(v1,v2)

t = u*v =(u1 * v2 - u2 * v1)得到的是平行四边形的面积或者相反数。

如果t > 0的得v在u的顺时针方向上(右边),如果t > 0得到v在u的逆时针方向(左边)。

在这里插入图片描述

Andrew’s Monotone chain算法

  1. 按照横坐标进行降序排序。之后按横坐标排序。
  2. 最左边的入栈,但不记录vis。
  3. 从左到右扫描,如果栈中不足两个数,直接入栈,否则看cross(st[-2], st[-1], p)是否小于0
    • 如果大于0,直接入栈,vis[p] = true;
    • 否则栈顶出栈, vis[top] = false;
  4. 到头之后,从右到左扫描,找不在栈中的vis[i] == false , 如果栈中不足m + 1个数字,直接入栈,否则看…
    • 如果大于0,直接入栈
    • 否则栈顶出栈。
  5. 栈顶需要出栈,因为两个0结点。
class Solution {
    
    /*pq * qr*/
    private boolean cross(int[] p, int[]q ,int[] r) {
       	return ((p[0] - q[0]) * (r[1] - q[1]) - (p[1] - q[1]) * (r[0] - q[0])) < 0;
    }
    
    
    
    public int[][] outerTrees(int[][] trees) {
        int n = trees.length;
        if (n < 4) {
            return trees;
        }
        /* 按照 x 大小进行排序,如果 x 相同,则按照 y 的大小进行排序 */
        Arrays.sort(trees, (a, b) -> {
            if (a[0] == b[0]) {
                return a[1] - b[1];
            }
            return a[0] - b[0];
        });
        List<Integer> hull = new ArrayList<Integer>();
        boolean[] used = new boolean[n];
        /* hull[0] 需要入栈两次,不进行标记 */
        hull.add(0);
        /* 求出凸包的下半部分 */
        for (int i = 1; i < n; i++) {
            while (hull.size() > 1 && cross(trees[hull.get(hull.size() - 2)], trees[hull.get(hull.size() - 1)], trees[i]) < 0) {
                used[hull.get(hull.size() - 1)] = false;
                hull.remove(hull.size() - 1);
            }
            used[i] = true;
            hull.add(i);
        }
        int m = hull.size();
        /* 求出凸包的上半部分 */
        for (int i = n - 2; i >= 0; i--) {
            if (!used[i]) {
                while (hull.size() > m && cross(trees[hull.get(hull.size() - 2)], trees[hull.get(hull.size() - 1)], trees[i]) < 0) {
                    used[hull.get(hull.size() - 1)] = false;
                    hull.remove(hull.size() - 1);
                }
                used[i] = true;
                hull.add(i);
            }
        }
        /* hull[0] 同时参与凸包的上半部分检测,因此需去掉重复的 hull[0] */
        hull.remove(hull.size() - 1);
        int size = hull.size();
        int[][] res = new int[size][2];
        for (int i = 0; i < size; i++) {
            res[i] = trees[hull.get(i)];
        }
        return res;
    }
    
  

    public int cross(int[] p, int[] q, int[] r) {
        return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
    }
}


总结

  • 栈可以使用数组进行优化。

  • 分别寻找下凸包和上凸包。沿着排好序的点,一定是逆时针(左拐)前进。那么cross(st[-2], st[-1], p) > 0的。

  • 另外进行判断的时候,寻找下凸包的时候,栈中元素是两个的时候直接入栈。

  • 寻找上凸包的时候,栈中元素是m的的时候就应该直接入栈了。最少有m + 1个,m个包括最右端点 + 1就是有两个了。

  • vis数组的意义是防止下凸包中的点在放入栈中,其实就是维护了当前的在凸包上的点。

  • 调试技巧,直接看结果,和答案排序后进行对比,看哪个除了问题。
  • 之后就可以定位到是求上凸包,还是下凸包出现了问题。
  • 还可以定位到是否是统计答案的时候出现了直接使用i而不是st[i]的情况

常见错误

  • 小于4个点的时候,所有的点都是凸包。如果不判断,有一个点的时候是错误的。
  • 排序不对,第二维必须排序,因为是从下到上。寻找下凸包。
  • vis数组忘记了
  • 判断的时候,cross中的p,q,r传递的不对

题目

  1. leetcode 安装栅栏 直接就是寻找的凸包的模板
### Halcon 中的凸包算法及其使用 在 Halcon 中,可以利用 `gen_convex_hull` 运算符来生成给定区域的凸包[^1]。该运算符接受一个输入区域并返回其对应的凸包区域。以下是关于此函数的具体说明以及示例代码。 #### 函数描述 `gen_convex_hull` 是用于计算二维点集或区域的最小包围凸多边形的功能。它能够有效地处理复杂的形状,并提供简化后的几何表示形式。通过调用这一操作符,用户可以获得目标对象的边界特征,这对于图像分析中的形态学应用非常有用。 #### 参数列表 - **InputRegion**: 输入的一个或多個二維區域。 - **ConvexHull**: 输出的结果——即原始輸入區域所對應的凸包。 下面是一段简单的 Python 脚本演示如何在 Halcon 环境下实现这一点: ```python from pyhalcon import * # 初始化 Halcon 图像处理环境 HDevWindowStack = [] with HDevProcedureBlock(): # 创建一个新的窗口句柄 WindowHandle = new_window(0, 0, 512, 512) # 定义测试数据 (例如一些随机分布的点) PointsX = [10, 70, 80, 90, 100] PointsY = [10, 30, 40, 60, 80] # 将离散点转换成Halocn可识别的形式 GenEmptyObj = gen_empty_obj() ConcatObj = concat_obj(GenEmptyObj, GenEmptyObj) for i in range(len(PointsX)): Row = PointsX[i]; Column = PointsY[i]; AddPoint = add_point(Row,Column) ConcatObj = concat_obj(ConcatObj,AddPoint) # 计算这些点构成的凸壳 ConvexHullResult = gen_convex_hull(ConcatObj,"outer") # 显示原有点集合与最终得到的凸壳图形对比效果 dev_display(WindowHandle,[ConcatObj]) set_color(WindowHandle,'red') dev_display(WindowHandle,[ConvexHullResult]) end_of_procedure() ``` 以上脚本展示了如何定义一组坐标点并通过 `gen_convex_hull` 来获取它们形成的凸包轮廓。最后还包含了可视化部分以便直观理解结果。 #### 注意事项 当执行上述程序时,请确保已安装最新版本的 HALCON 库文件和支持库;另外需要注意的是实际项目里可能还需要考虑更多细节比如异常情况下的错误捕获机制等问题[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值