Gym 101606B - Breaking Biscuits - [凸包+旋转卡壳][凸包的宽度]

题目链接:https://codeforces.com/gym/101606/problem/B

 

题解:

对于给出的 $n$ 个点,先求这些点的凸包,然后用旋转卡壳求出凸包的宽度(Width (minimum width) of a convex polygon)即可。

旋转卡壳求凸包的宽度和求凸包的直径(Diameter (maximum width) of a convex polygon)差不多。

 

AC代码:

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const double eps=1e-8;
const double INF=1e18;

int Sign(double x)
{
    if(x<-eps) return -1;
    if(x>eps) return 1;
    return 0;
}
int Cmp(double x,double y){return Sign(x-y);}

struct Point
{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator+(const Point &o)const{return Point(x+o.x,y+o.y);}
    Point operator-(const Point &o)const{return Point(x-o.x,y-o.y);}
    Point operator*(double k)const{return Point(x*k,y*k);}
    Point operator/(double k)const{return Point(x/k,y/k);}
    int operator==(const Point &o)const{return Cmp(x,o.x)==0 && Cmp(y,o.y)==0;}
    bool operator<(const Point &o)const
    {
        int sgn=Cmp(x,o.x);
        if(sgn==-1) return 1;
        else if(sgn==1) return 0;
        else return Cmp(y,o.y)==-1;
    }
    void print(){printf("%.11f %.11f\n",x,y);}
};
typedef Point Vctor;

//叉积
double Cross(Vctor A,Vctor B){return A.x*B.y-A.y*B.x;}
double Cross(Point O,Point A,Point B){return Cross(A-O,B-O);}

//距离
double Dot(Vctor A,Vctor B){return A.x*B.x+A.y*B.y;}
double Length(Vctor A){return sqrt(Dot(A,A));}
double Length(Point A,Point B){return Length(A-B);}

vector<Point> ConvexHull(vector<Point> P,int flag=1) //flag=0不严格 flag=1严格
{
    if(P.size()<=1) return P;
    int sz=P.size();
    vector<Point> ans(2*sz);
    sort(P.begin(),P.end());
    int now=-1;
    for(int i=0;i<sz;i++)
    {
        while(now>0 && Sign(Cross(ans[now]-ans[now-1],P[i]-ans[now-1]))<flag) now--;
        ans[++now]=P[i];
    }
    int pre=now;
    for(int i=sz-2;i>=0;i--)
    {
        while(now>pre && Sign(Cross(ans[now]-ans[now-1],P[i]-ans[now-1]))<flag) now--;
        ans[++now]=P[i];
    }
    ans.resize(now);
    return ans;
}

double RotatingCalipers(const vector<Point> &P) //旋转卡壳法
{
    double ans=INF;
    int sz=P.size();
    for(int i=0,q=1;i<sz;i++)
    {
        int j=(i+1)%sz;
        while( Cross(P[j]-P[i],P[q]-P[i]) < Cross(P[j]-P[i],P[(q+1)%sz]-P[i]) ) q=(q+1)%sz;
        double d=fabs(Cross(P[i],P[j],P[q]))/Length(P[i],P[j]);
        ans=min(ans,d);
    }
    return ans;
}

int n;
vector<Point> P;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        double x,y; cin>>x>>y;
        P.pb(Point(x,y));
    }
    double ans=RotatingCalipers(ConvexHull(P));
    printf("%.8f\n",ans);
}

 

posted @ 2019-04-16 21:04  Dilthey  阅读(312)  评论(0编辑  收藏  举报