模板題鏈接 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();
}