旋转卡壳(计算凸包的宽度)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30358129/article/details/82793066
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5+100;
struct P{
    ll x,y;
    P(ll _x=0,ll _y=0){x=_x;y=_y;}
    P operator -(P b)const{ 
        return P(x - b.x, y - b.y);
    }
    ll operator ^(P b)const{  //计算叉积
        return x*b.y - y*b.x;
    }
}s[N],ch[N];
int top,n,m;
ll cs(P p0,P p1,P p2){  //向量p0->p1 叉乘  向量p0->p2  
    return (p1.x-p0.x)*(p2.y-p0.y) - (p1.y-p0.y)*(p2.x-p0.x);
}
double pow2(double x){
    return x*x;
}
double dis(P p1,P p2){
    return sqrt(pow2(p1.x-p2.x)+pow2(p1.y-p2.y));
}
bool cmp(P p1,P p2){
    ll tmp = cs(s[0],p1,p2);
    if(tmp>0) return 1;
    if(tmp<0) return 0;
    return dis(s[0],p1)<dis(s[0],p2);
}
void init(){
    scanf("%d%d",&n,&m);
    P p0(0,1e9);
    int k;
    for(int i = 0;i < n;i ++){
        scanf("%lld%lld",&s[i].x,&s[i].y);
        if(p0.y>s[i].y||(p0.y==s[i].y&&p0.x>s[i].x)) p0 = s[i],k = i;
    }
    swap(s[0],s[k]);
    sort(s+1,s+n,cmp);  //极角排序,跳过第0个
}
void graham(){    //生成凸包,ch从0开始存放
    if(n==1) ch[top++] = s[0];
    else 
        for(int i = 0;i < n;i ++){
            while(top>1&&cs(ch[top-2],ch[top-1],s[i])<=0) top --;
            ch[top++] = s[i];
        }
}
double len(P a,P b,P c){   //两点式情况下点到直线的距离
    double s = fabs(cs(a,b,c));
    return s/dis(a,b);
}
double cps(){     //旋转卡壳
    if(top<=2) return 0;   //判断凸包退化成线段的情况
    double ans = 9e18;  
    int cur = 1; 
    for(int i = 1;i <= top;i ++){
        P v = ch[i-1] - ch[i%top];
        while((v^(ch[(cur+1)%top]-ch[cur]))<0) cur = (cur+1)%top;  
        ans = min(ans,len(ch[i-1],ch[i%top],ch[cur]));
    }
    return ans;
}
int main(){
    init();
    graham();
    printf("%.8f",cps());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30358129/article/details/82793066