凸包

前置知识

极角排序:按向量与\(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 
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) st;
stack  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=-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;
}

你可能感兴趣的:(凸包)