算法筆記_016:凸包問題(Java)


 目錄

1 問題描述

2 解決方案

2.1 蠻力法

 

 


1 問題描述

給定一個平面上n個點的集合,它的凸包就是包含所有這些點的最小凸多邊形,求取滿足此條件的所有點。

另外,形象生動的描述:

(1)我們可以把這個問題看作如何用長度最短的柵欄把n頭熟睡的老虎圍起來。

(2)也可以這樣看:請把所討論的點想象成釘在膠合板上的釘子,膠合板代表平面。撐開一根橡皮筋圈,把所有的釘子都圍住,然后啪一聲松開手。凸包就是以橡皮圈為邊界的區域。具體示意如下圖1所示:

 

 

圖1  用橡皮筋來解釋凸包

 

 


2 解決方案

2.1 蠻力法

使用蠻力法解決此問題比較簡單,具體思想:對於一個n個點集合中的兩個點p1p2,當且僅當該集合中的其它點都位於穿過這兩點的直線的同一邊時,它們的連線就是該集合凸包邊界的一部分,簡言之,p1p2就是凸包問題中最小凸多邊形的頂點。對每一對點都做一遍檢驗之后,滿足條件的線段就構成了該凸包的邊界。

此時,根據上面的公式,我們只需要把每個點代入公式ax+by-c,判斷公式計算結果的符號是否全部大於等於0或者小於等於0,如果是則是凸包邊界上的點,否則就不是。該算法的時間效率為0n^3)。具體代碼如下:

 

package com.liuzhen.chapterThree;

public class ConvexHull {
    //蠻力法解決凸包問題,返回點集合中凸多邊形的點集合
    public static Point[] getConvexPoint(Point[] A){
        Point[] result = new Point[A.length];
        int len = 0;  //用於計算最終返回結果中是凸包中點的個數
        for(int i = 0;i < A.length;i++){
            for(int j = 0;j < A.length;j++){
                if(j == i)     //除去選中作為確定直線的第一個點
                    continue;
                
                int[] judge = new int[A.length];   //存放點到直線距離所使用判斷公式的結果
                
                for(int k = 0;k < A.length;k++){
                    int a = A[j].getY() - A[i].getY();
                    int b = A[i].getX() - A[j].getX();
                    int c = (A[i].getX())*(A[j].getY()) - (A[i].getY())*(A[j].getX());

                    judge[k] = a*(A[k].getX()) + b*(A[k].getY()) - c;  //根據公式計算具體判斷結果
                }
                
                if(JudgeArray(judge)){  // 如果點均在直線的一邊,則相應的A[i]是凸包中的點
                    result[len++] = A[i];
                    break;
                }    
            }
        }
        Point[] result1 = new Point[len];
        for(int m = 0;m < len;m++)
            result1[m] = result[m];
        return result1;
    }
    
    //判斷數組中元素是否全部大於等於0或者小於等於0,如果是則返回true,否則返回false
    public static boolean JudgeArray(int[] Array){
        boolean judge = false;
        int len1 = 0, len2 = 0;
        
        for(int i = 0;i < Array.length;i++){
            if(Array[i] >= 0)
                len1++;
        }
        for(int j = 0;j < Array.length;j++){
            if(Array[j] <= 0)
                len2++;
        }
        
        if(len1 == Array.length || len2 == Array.length)
            judge = true;
        return judge;
    }
    
    public static void main(String[] args){
        Point[] A = new Point[8];
        A[0] = new Point(1,0);
        A[1] = new Point(0,1);
        A[2] = new Point(0,-1);
        A[3] = new Point(-1,0);
        A[4] = new Point(2,0);
        A[5] = new Point(0,2);
        A[6] = new Point(0,-2);
        A[7] = new Point(-2,0);
        
        Point[] result = getConvexPoint(A);
        System.out.println("集合A中滿足凸包的點集為:");
        for(int i = 0;i < result.length;i++)
            System.out.println("("+result[i].getX()+","+result[i].getY()+")");
    }
}

 上面定義的點Point類代碼如下:

package com.liuzhen.chapterThree;

public class Point {
    private int x;
    private int y;
    
    Point(){
        x = 0;
        y = 0;
    }
    
    Point(int x, int y){
        this.x = x;
        this.y = y;
    }
    
    public void setX(int x){
        this.x = x;
    }
    
    public int getX(){
        return x;
    }
    
    public void setY(int y){
        this.y = y;
    }
    
    public int getY(){
        return y;
    }
}

 

 

運行結果:

集合A中滿足凸包的點集為:
(2,0)
(0,2)
(0,-2)
(-2,0)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM