凸包问题向来是计算几何中最重要的问题之一,许多各式各样的应用大多要么本身就是图凸包问题要么其中一部分需要按照凸包问题解决。
凸集合定义:对于平面上一个点集合,如果集合中的任意两点p和q为端点的线段都属于该集合,那么称这个集合为凸集合。
凸包定义:一个点集合S的凸包是包含S的最小凸集合。我们可以假设有一块板子,板子上面有许多钉子,用一根橡皮筋将所有的钉子都围住,凸包就是以橡皮筋圈为边界的区域。
在坐标平面上穿过两个点(x1, x2),(x2, y2)的直线方程为 ax+by = c (其中a = y2- y1, b = x1 - x2, c = x1y2 - y1x2)
上述方程基于两点式直线方程
由两个点连起来的直线会将平面分成两部分,其中半个平面的点都满足ax+by>c ,另一半平面中的点都满足ax+by<c ,对于线上的点来说满足ax+by=c。因此,算法的思路就是对于每个点带入ax+by-c,判断表达式结果的符号是否相同即可。
import java.util.*;class Point {int x;int y;public Point(int x, int y) {this.x = x;this.y = y;}@Overridepublic String toString() {return "Point{" +"x=" + x +", y=" + y +'}';}
}
public class Main {public static void main(String[] args) {Point[] points = new Point[6];List arr = new ArrayList();points[0] = new Point(1,3);points[1] = new Point(2,1);points[2] = new Point(3,5);points[3] = new Point(4,4);points[4] = new Point(5,2);points[5] = new Point(3,2);arr = outerTrees(points);Iterator it = arr.iterator();while (it.hasNext()) {System.out.println(it.next().toString() + " ");}}private static List<Point> outerTrees(Point[] points) {Set<Point> ans = new HashSet<>();/*** 只有一个点* */if (points.length == 1){ans.add(points[0]);return new ArrayList<>(ans);}for (int i = 0; i < points.length-1; i++){for (int j = i + 1; j < points.length; j++){int oneSide = 0;for (int k = 0; k < points.length; k++){if (k == i || k == j) {continue;}if (calcuTriangle(points[i], points[j], points[k]) > 0){oneSide++;}}if (oneSide == points.length-2 || oneSide == 0){ans.add(points[i]);ans.add(points[j]);}int otherSide = 0;for (int k = 0; k < points.length; k++){if (k == i || k == j) continue;if (calcuTriangle(points[i], points[j], points[k]) < 0){otherSide++;}}if (otherSide == points.length-2 || otherSide == 0){ans.add(points[i]);ans.add(points[j]);}}}return new ArrayList<>(ans);}private static int calcuTriangle(Point a1, Point a2, Point a3) {return a1.x * a2.y + a3.x * a1.y + a2.x * a3.y - a3.x * a2.y - a2.x * a1.y - a1.x * a3.y;}
}