算法笔记_016:凸包问题(Java)

Posted 舞动的心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法笔记_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)

 

以上是关于算法笔记_016:凸包问题(Java)的主要内容,如果未能解决你的问题,请参考以下文章

016-kruskal算法-贪心-《算法设计技巧与分析》M.H.A学习笔记

凸包中的额外点(使用格雷厄姆扫描)错误+ java

挑战程序设计竞赛(算法和数据结构)——16.12凸包(安德鲁算法)的JAVA实现

算法笔记_160:算法提高 约数个数(Java)

算法笔记_116:算法集训之代码填空题集三(Java)

算法笔记_017:递归执行顺序的探讨(Java)