Graham算法求凸包

287 阅读1分钟

1. 向量叉积

定义cross(p,q,r)如下:

未命名图片.png

若cross(p,q,r)>0,则pq\overrightarrow{pq}方向经过逆时针旋转小于180°得到qr\overrightarrow{qr}方向,若cross(p,q,r)<0,则pq\overrightarrow{pq}方向经过顺时针旋转小于180°得到qr\overrightarrow{qr}方向,若cross(p,q,r)=0,pq\overrightarrow{pq}qr\overrightarrow{qr}同向或反向。

2. Graham算法

方法2

3. 例题

安装栅栏

class Solution {
public:

	double cross(const vector<int>& p, const vector<int>& q, const vector<int>& r) {
		double x1 = q[0] - p[0], y1 = q[1] - p[1];
		double x2 = r[0] - q[0], y2 = r[1] - q[1];
		return x1 * y2 - y1 * x2;
	}
	double dis(const vector<int>& a, const vector<int>& b) {
		return pow(a[0] - b[0], 2) + pow(a[1] - b[1], 2);
	}
	vector<vector<int>> outerTrees(vector<vector<int>>& trees) {
		if (trees.size() <= 3)
			return trees;
		int n = trees.size();
		int  ind = 0;
		for (int i = 0; i < n; i++)
			if (trees[i][0] < trees[ind][0] || trees[i][0] == trees[ind][0] && trees[i][1] < trees[ind][1]) {
				ind = i;
			}
		swap(trees[0], trees[ind]);
		sort(trees.begin() + 1, trees.end(), [&](const vector<int>& a, const vector<int>& b) {
			if (cross(trees[0], a, b) != 0)
				return cross(trees[0], a, b) > 0;
			else
				return dis(trees[0], a) < dis(trees[0], b);
			});
		int l = n - 1;
		while (l >= 0 && cross(trees[0], trees[n - 1], trees[l]) == 0)
			l--;
		for (int left = l + 1, right = n - 1; left < right; left++, right--) {
			swap(trees[left], trees[right]);
		}
		vector<vector<int>> ans{ trees[0],trees[1] };
		for (int i = 2; i < n; i++) {
			while (ans.size() >= 2 && cross(ans[ans.size() - 2], ans[ans.size() - 1], trees[i]) < 0)
				ans.pop_back();
			ans.push_back(trees[i]);
		}
		return ans;
	}
};