首先确定一个一定在凸包里的点 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;
}