Graham 求静态凸包

首先确定一个一定在凸包里的点 base, 比如 y 坐标最小的点。
然后用一个射线按照某种方式转一圈, 每一时刻只保留最外的点 x, 上一个加入凸包的点 y, 上上个 z, 显然 (z,y) 转到 (y,x) 需要 δ 的方向必须与原来射线转的方向一致。

在 base 为原点的意义下共线的两个向量, 比较长度只需比较 x 坐标的大小, 或是比较 y 坐标的大小。

下面是两份有细微区别的代码。
1

#include <bits/stdc++.h>
typedef double db;
using namespace std;

const int N = 1e5 + 23;
const db EPS = 1e-15;

struct po {
	db x , y;
	po() {
	}
	po(db x_, db y_) : x(x_), y(y_) {
	}
	inline po operator + (po b) {return po(x+b.x, y+b.y);}
	inline po operator - (po b) {return po(x-b.x, y-b.y);}
	inline db operator % (po b) {return x*b.y - y*b.x;}
	inline db len() {return sqrt(x*x+y*y);}
} p[N], s[N];

bool cmp(po s1, po s2) {
	db tmp = ((s1-p[1]) % (s2-p[1]));
	return (tmp < 0) || (tmp == 0 && s1.x < s2.x);
}

int n;

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%lf%lf", &p[i].x, &p[i].y);
		if(p[i].y < p[1].y) swap(p[1], p[i]);
	}
	sort(p+2, p+1+n, cmp);
	int cnt = 1;
	s[1] = p[1];
	for(int i = 2; i <= n; ++i) {
		while(cnt > 1 && (s[cnt]-s[cnt-1])%(p[i]-s[cnt]) >= 0) --cnt;
		s[++cnt] = p[i];
	}
	double ans = (s[cnt] - s[1]).len();
	for(int i = 1; i < cnt; ++i) ans += (s[i+1] - s[i]).len();
	printf("%.2lf", ans);
	return 0;
}

2

#include <bits/stdc++.h>
typedef double db;
using namespace std;

const int N = 1e5 + 23;
const db EPS = 1e-15;

struct po {
	db x , y;
	po() {
	}
	po(db x_, db y_) : x(x_), y(y_) {
	}
	inline po operator + (po b) {return po(x+b.x, y+b.y);}
	inline po operator - (po b) {return po(x-b.x, y-b.y);}
	inline db operator % (po b) {return x*b.y - y*b.x;}
	inline db len() {return sqrt(x*x+y*y);}
} p[N], s[N];

bool cmp(po s1, po s2) {
	db tmp = ((s1-p[1]) % (s2-p[1]));
	return (tmp > 0) || (tmp == 0 && s1.x < s2.x);
}

int n;

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%lf%lf", &p[i].x, &p[i].y);
		if(p[i].y < p[1].y) swap(p[1], p[i]);
	}
	sort(p+2, p+1+n, cmp);
	int cnt = 1;
	s[1] = p[1];
	for(int i = 2; i <= n; ++i) {
		while(cnt > 1 && (s[cnt]-s[cnt-1])%(p[i]-s[cnt]) <= 0) --cnt;
		s[++cnt] = p[i];
	}
	double ans = (s[cnt] - s[1]).len();
	for(int i = 1; i < cnt; ++i) ans += (s[i+1] - s[i]).len();
	printf("%.2lf", ans);
	return 0;
}
posted @ 2021-01-27 10:44  xwmwr  阅读(65)  评论(0编辑  收藏  举报