首先確定一個一定在凸包裏的點 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;
}