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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章