美文网首页
凸包问题:Graham's Scan解法

凸包问题:Graham's Scan解法

作者: I讨厌鬼I | 来源:发表于2019-09-28 10:25 被阅读0次

概念

凸包(Convex Hull)是一个计算几何(图形学)中的概念。用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有点的。

问题

给定平面的点集,求出凸包的所有顶点。

算法思路

Grahanm's Scan算法的主要思路如下:
1,选择P中y坐标最小的点为起始点p0,若有多个这样的点则进一步选取其中x坐标最小的点为p0;

2,设<p1,p2,……,pm>P中剩余的点,对其按逆时针方向相对p0的极角进行从小到大排序,若有多个点有相同的极角,则离p0点近的排在前面;

3,设排序后的点的顺序为p1,p2,……,pm,分别计算向量p0p1p1p2的叉积,二维矢量的叉积a × b = IaI•IbIsinθθ为从ab的夹角,如果ba的逆时针方向,则sinθ为正,叉积也就为正,在我们逆时针遍历的情况下,如果ba的顺时针方向,则p1点必定不是凸包上的点,反之则是在凸包上的点。所以我们使用栈来保存凸包上的点,遍历过程中发现栈顶的点不是凸包上的点就pop出来,如果是就继续把接下来的点放入栈中。

图片可能更容易理解,这里就放几张别人博客的图片:


Grahanm's Scan

JAVA实现

import java.util.*;

public class Main {

    static class Point {
        int x;
        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }

    // 用于存储起始点
    public static Point centerPoint;

    // 叉积
    public static int CJ(int x1, int y1, int x2, int y2){
        return x1*y2 - x2*y1;
    }

    // 计算向量(p1->p2)和(p2->p3)两个向量的叉积
    public static int compare(Point p1, Point p2, Point p3){
        return CJ(p2.x-p1.x, p2.y - p1.y, p3.x-p2.x, p3.y-p2.y);
    }

    public static void main(String arg[]){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        List<Point> points = new ArrayList<>();
        for (int i=0; i<n; i++){
            int x = in.nextInt();
            int y = in.nextInt();
            Point point = new Point(x, y);
            // 找到x,y都最小的点作为起始点
            if (centerPoint == null || centerPoint.y>point.y || (centerPoint.y==point.y && centerPoint.x>point.x)){
                centerPoint = point;
            }
            points.add(point);
        }
        // 把起始点拿出去
        points.remove(centerPoint);

        // 按照与起始点向量的极角排序
        Collections.sort(points, (p1, p2) -> {
            if (Math.atan2(p1.y- centerPoint.y, p1.x- centerPoint.x) != Math.atan2(p2.y- centerPoint.y, p2.x- centerPoint.x)){
                // atan2可以计算极角
                return Math.atan2(p1.y- centerPoint.y, p1.x- centerPoint.x) < Math.atan2(p2.y- centerPoint.y, p2.x- centerPoint.x)? -1 : 1;
            }
            // 极角相同与中心点距离越近,则x坐标也就越近
            return Math.abs(p1.x- centerPoint.x) - Math.abs(p2.x- centerPoint.x);
        });

        // 用数组模拟栈
        Point[] stack = new Point[n];
        stack[0] = centerPoint;
        // 栈顶指针
        int top = 0;

        // 遍历点集中每一个点
        for (int i=0; i<points.size();){
            //如果栈中元素大于等于2并且(p2->p3)在(p1->p2)的顺时针方向,栈顶的点抛出
            while (top>=1&&compare(stack[top-1], stack[top], points.get(i)) < 0) top--;
            // 找到在逆时针方向的点了,将p2放入栈顶
            stack[++top] = points.get(i++);
        }

        // 输出栈中的所有点就是凸包上的点
        for (int i=0; i<=top; i++){
            System.out.println(stack[i]);
        }
    }
}

参考

算法作业-凸包问题-Graham方法
凸包:Graham's Scan

相关文章

  • 凸包问题:Graham's Scan解法

    概念 凸包(Convex Hull)是一个计算几何(图形学)中的概念。用不严谨的话来讲,给定二维平面上的点集,凸包...

  • 凸包:Graham's Scan

    1.概念 凸包(Convex Hull)是一个计算几何(图形学)中的概念。用不严谨的话来讲,给定二维平面上的点集,...

  • 凸包

    凸包最常用的凸包算法是Graham扫描法和Jarvis步进法Graham's Scan法这个算法是由数学大师葛立恒...

  • Python3 趣味系列题8 ------ 凸包动态绘制

    本文介绍利用Graham Scan算法获得凸包(平面凸包),并动态展示凸包的形成过程。下面用比较通俗的语言,介绍下...

  • 凸包问题——Graham扫描法

    凸包(Convex Hull)是一个计算几何(图形学)中的概念。在一个实数向量空间中,对于给定集合X,所有包含X的...

  • 图像轮廓(2)

    1. 凸包 凸缺陷可以用来处理手势识别问题 points:轮廓clockwise:True:凸包按顺时针方向排列;...

  • [Computational Geometry] Analogy

    "Graham's scanis the most popular and fundamental method ...

  • 凸包

    向量的叉乘就是由该两个向量所组成的平行四边形的面积(x1y2-x2y1).这个凸包不是太懂.先留模板在此这个是水平...

  • 凸包

    convexHull 实例

  • 凸包

    逼近多边形是轮廓的高度近似,但是有时候我们希望使用一个多边形的凸包来简化它。凸包跟逼近多边形很像,只不过它是物体最...

网友评论

      本文标题:凸包问题:Graham's Scan解法

      本文链接:https://www.haomeiwen.com/subject/bgehyctx.html