解题思路
极角:纵坐标比横坐标
y 1 / x 1 y1/x1 y1/x1 与 y 2 / x 2 y2/x2 y2/x2比较 即 p 0 p 1 p 2 p0p1p2 p0p1p2的叉积 x 1 ∗ y 2 − x 2 ∗ y 1 x1*y2-x2*y1 x1∗y2−x2∗y1的正负来判断极解的大小。
详解见 凸包
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#define ll long long
#define db double
using namespace std;
int n,cnt;
db x;
struct c {
db x,y;
} a[100010],s[100010];
db work(c a,c b)
{
return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
}
db check(c k,c x,c y)
{
return (x.x-k.x)*(y.y-k.y)-(x.y-k.y)*(y.x-k.x);
}
bool cmp(c l,c r)
{
db t=check(a[1],l,r);
if(t>0)return 1;
if(t==0&&work(a[0],l)<work(a[0],r))
return 1;
return 0;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%lf%lf",&a[i].x,&a[i].y);
if(i!=1)
{
if(a[i].y<a[1].y||(a[i].y==a[1].y&&a[i].x<a[1].x))
swap(a[1],a[i]);
}
}
sort(a+2,a+n+1,cmp);
s[++cnt]=a[1];
for(int i=2; i<=n; i++) {
while(cnt>1&&check(s[cnt-1],s[cnt],a[i])<=0)
cnt--;
s[++cnt]=a[i];
}
s[++cnt]=a[1];
db ans=0;
for(int i=1; i<cnt; i++) {
ans=ans+work(s[i],s[i+1]);
}
printf("%.2lf",ans);
}