c++ Java 二維凸包 Andrew 算法模板

模板題鏈接 P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二維凸包

先排序(先按 y 再按 x ),然後計算凸包,一共兩次掃描,第一次計算下凸包,第二次計算上凸包(計算上凸包的時候可以不用判斷top,如果要判斷可以加一個top大於下凸包的元素個數)

附上c++模板

#include <iostream>
#include <memory>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#define MAXN 100001
using namespace std;
/* 向量 */
struct Vertex {
	double x, y;
	Vertex(const double & _x = double(), const double & _y = double()) : x(_x), y(_y) {}
};
/* 點 */
struct Point {
	double x, y;
	Point(const double & _x = double(), const double & _y = double()) : x(_x), y(_y) {}
} points[MAXN];
/* 計算叉積 */
inline double cross(const Vertex & a, const Vertex & b) {
	return a.x * b.y - a.y * b.x;
}
/* 計算叉積<a, b> * <a, c> */
inline double cross(const Point & a, const Point & b, const Point & c) {
	Vertex vab = Vertex(b.x - a.x, b.y - a.y);
	Vertex vac = Vertex(c.x - a.x, c.y - a.y);
	return cross(vab, vac);
}
/* 計算兩點間的距離 */
inline double dist(const Point & a, const Point & b) {
	double dx = a.x - b.x;
	double dy = a.y - b.y;
	return sqrt(dx * dx + dy * dy);
}
inline bool cmp(const Point & p1, const Point & p2) {
	if (p1.y == p2.y) {
		return p1.x < p2.x;
	}
	return p1.y < p2.y;
}
double Andrew(const int & n) {
	double ans = 0.0f;
	sort(points, points + n, cmp);
	int stack[MAXN] = { 0, 1 };
	int top = 1;
	for (int i = 2; i < n; ++i) {
		while (top && cross(points[stack[top - 1]], points[stack[top]], points[i]) <= 0) {
			--top;
		}
		stack[++top] = i;
	}
	stack[++top] = n - 2;
	for (int i = n - 3; i >= 0; --i) {
		while (cross(points[stack[top - 1]], points[stack[top]], points[i]) <= 0) {
			--top;
		}
		stack[++top] = i;
	}
	for (int i = 0; i < top - 1; ++i) {
		ans += dist(points[stack[i]], points[stack[i + 1]]);
	}
	ans += dist(points[stack[0]], points[stack[top - 1]]);
	return ans;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> points[i].x >> points[i].y;
	}
	double ans = Andrew(n);
	printf("%.2lf", ans);
	return 0;
}

Java版

Java版的題目鏈接 lab0實習

	/**
	 * Given a set of points, compute the convex hull, the smallest convex set that
	 * contains all the points in a set of input points. The gift-wrapping algorithm
	 * is one simple approach to this problem, and there are other algorithms too.
	 * 
	 * @param points a set of points with xCoords and yCoords. It might be empty,
	 *               contain only 1 point, two points or more.
	 * @return minimal subset of the input points that form the vertices of the
	 *         perimeter of the convex hull
	 */
	public static Set<Point> convexHull(Set<Point> points) {
		/*
		 * implements with Andrew Algorithm T(n) = O(nlogn) S(n) = O(n)
		 */
		Set<Point> convexHullSet = new HashSet<Point>();
		List<Point> pointList = new ArrayList<Point>();
		int pointNum = points.size();
		if (pointNum < 3) {
			return points;
		}
		for (Point point : points) {
			pointList.add(point);
		}
		pointList.sort(new Comparator<Point>() {
			@Override
			public int compare(Point o1, Point o2) {
				return 0 == Double.compare(o1.y(), o2.y()) ? (int) (o1.x() - o2.x()) : (int) (o1.y() - o2.y());
			}
		});
		int[] stack = new int[pointNum + 1];
		/* first, add two start point */
		stack[0] = 0;
		stack[1] = 1;
		int top = 1;
		for (int i = 2; i < pointNum; ++i) {
			/*
			 * while the cross product of the top two points and the new point is no more
			 * than 0 the top point will be replaced by the new point
			 */
			while (top > 0 && cross(pointList.get(stack[top - 1]), pointList.get(stack[top]), pointList.get(i)) <= 0) {
				--top;
			}
			stack[++top] = i;
		}
		/* do it again to calculate the upper convex hull */
		stack[++top] = pointNum - 2;
		for (int i = pointNum - 3; i >= 0; --i) {
			while (top > 0 && cross(pointList.get(stack[top - 1]), pointList.get(stack[top]), pointList.get(i)) <= 0) {
				--top;
			}
			stack[++top] = i;
		}
		for (int i = 0; i < top; ++i) {
			convexHullSet.add(pointList.get(stack[i]));
		}
		return convexHullSet;
	}

	/**
	 * calculate the cross product(<a, b> * <a, c>)
	 * 
	 * @param a a point
	 * @param b a point
	 * @param c a point
	 * @return the cross product of the vertex<a, b> and vertex<a, c>
	 */
	private static double cross(Point a, Point b, Point c) {
		/* use the point class to represent a vertex */
		Point vab = new Point(b.x() - a.x(), b.y() - a.y());
		Point vac = new Point(c.x() - a.x(), c.y() - a.y());
		return vab.x() * vac.y() - vab.y() * vac.x();
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章