凸包問題:Graham's Scan解法

概念

凸包(Convex Hull)是一個(gè)計(jì)算幾何(圖形學(xué))中的概念。用不嚴(yán)謹(jǐn)?shù)脑拋碇v,給定二維平面上的點(diǎn)集,凸包就是將最外層的點(diǎn)連接起來構(gòu)成的凸多邊型,它能包含點(diǎn)集中所有點(diǎn)的。

問題

給定平面的點(diǎn)集,求出凸包的所有頂點(diǎn)。

算法思路

Grahanm's Scan算法的主要思路如下:
1,選擇P中y坐標(biāo)最小的點(diǎn)為起始點(diǎn)p0,若有多個(gè)這樣的點(diǎn)則進(jìn)一步選取其中x坐標(biāo)最小的點(diǎn)為p0;

2,設(shè)<p1,p2,……,pm>P中剩余的點(diǎn),對(duì)其按逆時(shí)針方向相對(duì)p0的極角進(jìn)行從小到大排序,若有多個(gè)點(diǎn)有相同的極角,則離p0點(diǎn)近的排在前面;

3,設(shè)排序后的點(diǎn)的順序?yàn)?strong>p1,p2,……,pm,分別計(jì)算向量p0p1p1p2的叉積,二維矢量的叉積a × b = IaI?IbIsinθ,θ為從ab的夾角,如果ba的逆時(shí)針方向,則sinθ為正,叉積也就為正,在我們逆時(shí)針遍歷的情況下,如果ba的順時(shí)針方向,則p1點(diǎn)必定不是凸包上的點(diǎn),反之則是在凸包上的點(diǎn)。所以我們使用棧來保存凸包上的點(diǎn),遍歷過程中發(fā)現(xiàn)棧頂?shù)狞c(diǎn)不是凸包上的點(diǎn)就pop出來,如果是就繼續(xù)把接下來的點(diǎn)放入棧中。

圖片可能更容易理解,這里就放幾張別人博客的圖片:


Grahanm's Scan

JAVA實(shí)現(xiàn)

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 +
                    '}';
        }
    }

    // 用于存儲(chǔ)起始點(diǎn)
    public static Point centerPoint;

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

    // 計(jì)算向量(p1->p2)和(p2->p3)兩個(gè)向量的叉積
    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都最小的點(diǎn)作為起始點(diǎn)
            if (centerPoint == null || centerPoint.y>point.y || (centerPoint.y==point.y && centerPoint.x>point.x)){
                centerPoint = point;
            }
            points.add(point);
        }
        // 把起始點(diǎn)拿出去
        points.remove(centerPoint);

        // 按照與起始點(diǎn)向量的極角排序
        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可以計(jì)算極角
                return Math.atan2(p1.y- centerPoint.y, p1.x- centerPoint.x) < Math.atan2(p2.y- centerPoint.y, p2.x- centerPoint.x)? -1 : 1;
            }
            // 極角相同與中心點(diǎn)距離越近,則x坐標(biāo)也就越近
            return Math.abs(p1.x- centerPoint.x) - Math.abs(p2.x- centerPoint.x);
        });

        // 用數(shù)組模擬棧
        Point[] stack = new Point[n];
        stack[0] = centerPoint;
        // 棧頂指針
        int top = 0;

        // 遍歷點(diǎn)集中每一個(gè)點(diǎn)
        for (int i=0; i<points.size();){
            //如果棧中元素大于等于2并且(p2->p3)在(p1->p2)的順時(shí)針方向,棧頂?shù)狞c(diǎn)拋出
            while (top>=1&&compare(stack[top-1], stack[top], points.get(i)) < 0) top--;
            // 找到在逆時(shí)針方向的點(diǎn)了,將p2放入棧頂
            stack[++top] = points.get(i++);
        }

        // 輸出棧中的所有點(diǎn)就是凸包上的點(diǎn)
        for (int i=0; i<=top; i++){
            System.out.println(stack[i]);
        }
    }
}

參考

算法作業(yè)-凸包問題-Graham方法
凸包:Graham's Scan

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.概念 凸包(Convex Hull)是一個(gè)計(jì)算幾何(圖形學(xué))中的概念。用不嚴(yán)謹(jǐn)?shù)脑拋碇v,給定二維平面上的點(diǎn)集,...
    三三de酒閱讀 4,139評(píng)論 0 1
  • 凸包(Convex Hull)是一個(gè)計(jì)算幾何(圖形學(xué))中的概念。在一個(gè)實(shí)數(shù)向量空間中,對(duì)于給定集合X,所有包含X的...
    其實(shí)我很菜啊閱讀 3,546評(píng)論 0 0
  • 本文介紹利用Graham Scan算法獲得凸包(平面凸包),并動(dòng)態(tài)展示凸包的形成過程。下面用比較通俗的語言,介紹下...
    AiFany閱讀 1,385評(píng)論 0 1
  • 專業(yè)考題類型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項(xiàng)A選項(xiàng)B選項(xiàng)C選項(xiàng)D選項(xiàng)E選項(xiàng)F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 10,573評(píng)論 0 13
  • 一、叉積叉積的計(jì)算是線段方法的核心。對(duì)于向來p1和p2,叉積是由點(diǎn)(0,0)、p1、p2和p1+p2構(gòu)成的平行四邊...
    tdeblog閱讀 961評(píng)論 0 1

友情鏈接更多精彩內(nèi)容