旋轉卡殼(計算凸包的寬度)
阿新 • • 發佈:2018-11-10
#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;
}