1. 程式人生 > >旋轉卡殼(計算凸包的寬度)

旋轉卡殼(計算凸包的寬度)

#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; }