凸包
前置知识
极角排序:按向量与\(x\)轴的极角排序,\(\theta\in [0,2\pi]\)。
向量差集:\(\vec a\times\vec b=x_ay_b-x_by_a\),可以发现极角排序中若\(\vec a\lt \vec b,\vec a\times \vec b\gt 0\) 。
凸包
先找到所有点中最下面的点,多个最下面则取最左边。
然后按照这个点为原点\(O\),对其它点\(P\)的向量\(\overrightarrow {OP}\)极角排序。排序后呈现类似扇形顺序。
然后每次按顺序丢入点\(p_i\),\(p_i\)和凸包内前一个点形成的向量\(\overrightarrow {p_ip_{i-1}}\),若\(\overrightarrow {p_ip_{i-1}}\times \overrightarrow {p_{i-1}p_{i-2}}>0\),说明\(p_{i-1}\)成凹陷进去的一个顶点了,于是把\(p_{i-1}\)删除。依次这样添加即可。
模板题:P2742
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double pi = acos(-1.0);
const int MAXN=10005;
int n,cnt;
struct vec {
double x=0.0,y=0.0;
int id=0;
vec(double X=0,double Y=0,int ID=0){
x=X,y=Y,id=ID;
}
}p[MAXN],o,ax[MAXN];//Point : X (x,y) , O (x,y) ; Vector : AX_id (x,y)
vec operator + (vec aa,vec bb){ return (vec){aa.x+bb.x, aa.x+bb.y,0}; }
vec operator - (const vec &aa,const vec &bb){return (vec){aa.x-bb.x,aa.y-bb.y,0};}
double operator * (const vec &aa,const vec &bb){return aa.x*bb.x+aa.y*bb.y;}
double operator ^ (const vec &aa,const vec &bb){return aa.x*bb.y-aa.y*bb.x;}
vec operator * (const double bb,const vec &aa){return (vec){bb*aa.x,bb*aa.y,aa.id};}
vec rotate (vec aa,double bb){
return (vec){cos(bb)*aa.x-sin(bb)*aa.y,sin(bb)*aa.x+cos(bb)*aa.y,aa.id};
}
double dis(const vec &aa){
return sqrt(aa.x*aa.x+aa.y*aa.y);
}
bool cmp (const vec &aa,const vec &bb){//Sort the vector AX_i
if(fabs(aa^bb) > eps)return (aa^bb) > eps;
else {
return fabs(aa.x)<fabs(bb.x);
}
}
stack <vec> st;
stack <vec> pt;
int main(){
o.x=1e17,o.y=1e17;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);
p[i].id=i;
if(p[i].y<o.y-eps)o.y=p[i].y,o.x=p[i].x,o.id=i;
if(fabs(p[i].y-o.y)<=eps&&p[i].x<o.x)o.y=p[i].y,o.x=p[i].x,o.id=i;
}
for(int i=1;i<=n;i++){
if(i==o.id)continue;
cnt++;
ax[cnt]=p[i]-p[o.id];
ax[cnt].id=i;
}
sort(ax+1,ax+1+cnt,cmp);
st.push(p[ax[1].id]-p[o.id]);
pt.push(p[o.id]);pt.push(p[ax[1].id]);
for(int i=2;i<=cnt;i++){
while(!st.empty()&&((p[ax[i].id]-pt.top())^(st.top()))>=-eps)
st.pop(),pt.pop();
st.push(p[ax[i].id]-pt.top());
pt.push(p[ax[i].id]);
}
double ans=0.0;
while(!st.empty()){
ans+=dis(st.top());
st.pop();
}
ans+=dis((vec){pt.top()-p[o.id]});
printf("%.2f\n",ans);
return 0;
}