【墨鳌】【凸包算法:Andrew算法 & Graham算法】
解题思路
- 思路显而易见,计算几何求凸包
- Orz大佬,这Python代码绝绝子 @z1m
补充
2022/4/23
补充Graham算法
Andrew算法
C++版本
class Solution {
public:
vector<vector<int>> outerTrees(vector<vector<int>>& trees) {
auto cross=[](vector<int>&a,vector<int>&b,vector<int>&c){
return (b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0]);
};
int n=trees.size();
if(n<3)return trees;
sort(begin(trees),end(trees),[](auto&a,auto&b){
return make_pair(a[0],a[1])<make_pair(b[0],b[1]);
});
vector<vector<int>>low;
for(auto&p:trees){
while(low.size()>1 && cross(low[low.size()-1],low[low.size()-2],p)<0)low.pop_back();
low.push_back(p);
}
reverse(begin(trees),end(trees));
vector<vector<int>>top;
for(auto&p:trees){
while(top.size()>1 && cross(top[top.size()-1],top[top.size()-2],p)<0)top.pop_back();
top.push_back(p);
}
set<pair<int,int>>s;
for(auto&p:low)s.insert(make_pair(p[0],p[1]));
for(auto&p:top)s.insert(make_pair(p[0],p[1]));
vector<vector<int>>ans;
for(auto[x,y]:s)ans.push_back({x,y});
return ans;
}
};
Python版本
class Solution:
def outerTrees(self, points: List[List[int]]) -> List[List[int]]:
n = len(points)
if n < 3: return points
points.sort(key = lambda x:(x[0],x[1]))
cross = lambda a,b,c:(b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0])
lower = []
for p in points:
while len(lower) > 1 and cross(lower[-2],lower[-1],p) < 0: lower.pop()
lower.append((p[0],p[1]))
upper = []
for p in reversed(points):
while len(upper) > 1 and cross(upper[-2],upper[-1],p) < 0: upper.pop()
upper.append((p[0],p[1]))
return list(set(lower[:-1] + upper[:-1]))
- 不要被长度吓到了,前面全是计算几何的板子
Graham算法
//
// 有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
// Created by Mo-Ao on 2022/4/23.
//
#ifndef TESTDEMO_SOLUTION_H
#define TESTDEMO_SOLUTION_H
#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db eps = 1e-7;
const db pi = acos(-1.0);
struct Point {
db x, y;
Point(db x, db y) : x(x), y(y) {}
bool operator<(const Point &o) const { return x != o.x ? x < o.x : y < o.y; }
Point operator-(const Point &o) const { return Point(x - o.x, y - o.y); }
Point operator+(const Point &o) const { return Point(x + o.x, y + o.y); }
db operator&(const Point &o) const { return x * o.y - y * o.x; }
db length() const { return sqrt(x * x + y * y); }
void print() const {
printf("(%lf,%lf)\n", x, y);
}
};
typedef Point Vector;
db length(Point A, Point B) {
Vector AB = B - A;
return AB.length();
}
struct Polygon {
vector<Point> points;
void push(db x, db y) {
points.emplace_back(x, y);
}
void push(Point P) {
points.push_back(P);
}
void polarAngleSort() {
Point &O = points[0];
for (auto &P: points)if (P < O) swap(O, P);
sort(begin(points)+1, end(points), [&](auto &A, auto &B) {
db x = (A - O) & (B - O);
if (x > eps) return true;
if (x < -eps) return false;
return length(O, A) < length(O, B);
});
}
Point getBack(int i) {
return *(points.end() - i);
}
Point get(int i) {
return *(points.begin() + i);
}
int size() {
return points.size();
}
void print() {
for (auto &point: points) {
point.print();
}
}
};
void Graham(Polygon &R, Polygon &A) {
A.push(R.points[0]);
A.push(R.points[1]);
int n = R.points.size();
for (int i = 2; i < n; i++) {
Point P = R.get(i);
while (A.size() > 1 && (((A.getBack(2) - P) & (A.getBack(1) - P)) < -eps))
A.points.pop_back();
A.push(P);
}
}
class Solution {
public:
vector<vector<int>> outerTrees(vector<vector<int>> &trees) {
if(trees.size()<=3)return trees;
Polygon input, ans;
for (auto &tree: trees)
input.push(tree[0], tree[1]);
input.polarAngleSort();
input.print();
//cout << "---" << endl;
Graham(input, ans);
vector<vector<int>> res;
set<pair<int, int>> s;
for (auto &point: ans.points) {
res.push_back({(int) point.x, (int) point.y});
s.insert(make_pair((int) point.x, (int) point.y));
}
reverse(input.points.begin(), input.points.end());
Point A = ans.getBack(1);
Point B = ans.get(0);
for (auto &point: input.points) {
auto P = make_pair((int) point.x, (int) point.y);
if (s.count(P) == 0) {
if (((A - point) & (B - point)) == 0) res.push_back({P.first, P.second});
}
}
return res;
//polygon.print();
//convexHull.print();
}
};
#endif //TESTDEMO_SOLUTION_H
~~Jason_liu O(∩_∩)O