分治法解决平面集凸包问题

用分治法解决平面集问题就是把问题分割成更小的子问题,
运用递归的思想来对小问题求解,最后得到原问题的答案

分治法解决平面集凸包问题_第1张图片
如图所示,分治法解决凸包问题的步骤主要是:

  • 找到x方向的两个端点 p 1 p_1 p1 p n p_n pn,加入凸包的端点内
  • p 1 p n p_1p_n p1pn连线的上方找凸包的上部分端点 (递归实现)
    p 1 p n p_1p_n p1pn上部分的点中找到距离最远的点pmax,加入凸包端点内
    p 1 p_1 p1pmax内重复找上端点的操作
    在pmax p n p_n pn内重复找上端点的操作
  • p 1 p n p_1p_n p1pn连线的下方找凸包的下部分端点 (递归实现)
    p 1 p n p_1p_n p1pn下部分的点中找到距离最远的点pmax,加入凸包端点内
    p 1 p_1 p1pmax内重复找下端点的操作
    在pmax p n p_n pn内重复找下端点的操作

用java实现中遇到的问题:
Q:寻找距离直线最远的点,从哪些点内寻找
A:先对所有的点进行排序,可能的最远点的集合就为x落在线段之间内的点
Q:递归的结束条件
A:当找到的点到直线的最远距离为0时,递归就可以结束了

代码有一点点问题,如果三个点在一条直线上且都为凸包的端点,则只会输出两个端点。此问题可以通过改变递归的终止条件来解决。

java代码(仅供参考,数据集很小,只有十个点):

package Code.src.algorithm;
import java.util.*;
class Point{
    int x;
    int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}
public class GraphTheory_TuPackage {
    public static void main(String[] args){
        ArrayList<Point> PointArr = new ArrayList<Point>();
        PointArr.add(new Point(0,-1));PointArr.add(new Point(1,1));PointArr.add(new Point(2,2));PointArr.add(new Point(3,1));
        PointArr.add(new Point(4,2));PointArr.add(new Point(1,-3));PointArr.add(new Point(3,-1));PointArr.add(new Point(4,-2));
        PointArr.add(new Point(5,-1));PointArr.add(new Point(4,-4));PointArr.add(new Point(0,0));
//        ArrayListPrintf(PointArr);
        //重写排序方法,按x从小到大排序
        Collections.sort(PointArr, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                if (o1.x < o2.x)
                    return -1;
                if (o1.x > o2.x)
                    return 1;
                return 0;
            }
        });
//        ArrayListPrintf(PointArr);
        int left = 0; int right = PointArr.size()-1;
        ArrayList<Point> Duandian = new ArrayList<Point>();
        //x方向上的两个极值点加入数组
        Duandian.add(PointArr.get(left));Duandian.add(PointArr.get(right));
        //寻找上包部分的端点
        findUpPoint(left, right, PointArr, Duandian);
        //寻找下包部分的端点
        findDownPoint(left, right, PointArr, Duandian);
        ArrayListPrintf(Duandian);
    }
    //寻找凸包上半部分的端点
    public static void findUpPoint(int left, int right, ArrayList<Point> PointArr, ArrayList<Point> Duandian){
        int distance = Integer.MIN_VALUE;
        int best = 0;
        Point pointLeft = PointArr.get(left);
        Point pointRight = PointArr.get(right);
        //x在left和right之间的点为目标点,进行遍历
        for (int i=left; i<=right; i++){
            Point pointNow = PointArr.get(i);
            int distance_now = get_distance(pointLeft, pointRight, pointNow);
            //找到距离直线最远的点
            if (distance_now > distance){
                distance = distance_now;
                best = i;
            }
        }
        //如果没有目标点(或者目标点就在线段上),递归结束
        if (distance != 0){
            Duandian.add(PointArr.get(best));
            findUpPoint(left, best, PointArr, Duandian);
            findUpPoint(best, right, PointArr, Duandian);
        }
    }
    //寻找凸包下半部分的端点
    public static void findDownPoint(int left, int right, ArrayList<Point> PointArr, ArrayList<Point> Duandian){
        int distance = Integer.MAX_VALUE;
        int best = 0;
        Point leftPoint = PointArr.get(left);
        Point rightPoint = PointArr.get(right);
        for (int i=left; i<=right; i++){
            Point pointNow = PointArr.get(i);
            int distance_now = get_distance(leftPoint, rightPoint, pointNow);
            if (distance_now < distance){
                distance = distance_now;
                best = i;
            }
        }
        if (distance != 0){
            Duandian.add(PointArr.get(best));
            findDownPoint(left, best, PointArr, Duandian);
            findDownPoint(best, right, PointArr, Duandian);
        }
    }
    //c点到直线ab的距离公式
    public static int get_distance(Point a, Point b, Point c){
        return (a.x*b.y+b.x*c.y+c.x*a.y)-(a.x*c.y+b.x*a.y+c.x*b.y);
    }
    public static void ArrayListPrintf(ArrayList<Point> a){
        for (int i=0;i<a.size();i++)
            System.out.print(a.get(i).x+" "+a.get(i).y+"; ");
        System.out.println();
    }
}

你可能感兴趣的:(分治法解决平面集凸包问题)