Codeforces Gym - 101635K Blowing Candles [旋转卡壳]

题意:给你平面上一些点,求一个凸包的最短直径

思路:旋转卡壳,然后搞一下就行了可旋转卡壳求最远点差不多,cur带表的是求出的对锺点,然后与当前的直线p[i],p[i+1],求一下距离

代码:

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-16;
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct point
{
    double x,y;
    point(int _x = 0,int _y = 0)
    {
        x = _x;
        y = _y;
    }
    point operator -(const point &b)const
    {
        return point(x - b.x, y - b.y);
    }
    double operator ^(const point &b)const
    {
        return x*b.y - y*b.x;
    }
    double operator *(const point &b)const
    {
        return x*b.x + y*b.y;
    }
    void sc()
    {
        scanf("%lf%lf",&x,&y);
    }
};

struct Line
{
    point s,e;
    Line() {}
    Line(point _s,point _e)
    {
        s = _s;
        e = _e;
    }
    pair<int,point> operator &(const Line &b)const
    {
        point res = s;
        if(sgn((s-e)^(b.s-b.e)) == 0)
        {
            if(sgn((s-b.e)^(b.s-b.e)) == 0)
                return make_pair(0,res);
            else return make_pair(1,res);
        }
        double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
        res.x += (e.x-s.x)*t;
        res.y += (e.y-s.y)*t;
        return make_pair(2,res);
    }
};
double dist(point a,point b)
{
    return (double)sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point NearestpointToLineSeg(point P,Line L)
{
    point result;
    double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
    if(t >= 0.000 && t <= 1.0000)
    {
        result.x = L.s.x + (L.e.x - L.s.x)*t;
        result.y = L.s.y + (L.e.y - L.s.y)*t;
    }
    else
    {
        if(dist(P,L.s) < dist(P,L.e))
            result = L.s;
        else result = L.e;
    }
    return result;
}
double emmm(point P,Line L)
{
    point zz=NearestpointToLineSeg(P,L);
    return dist(zz,P);
}
const int MAXN = 2e5+7;
point List[MAXN];
int Stack[MAXN],top;
bool _cmp(point p1,point p2)
{
    double tmp = (p1-List[0])^(p2-List[0]);
    if(tmp > 0)return true;
    else if(tmp == 0 && dist(p1,List[0]) <= dist(p2,List[0]))
        return true;
    else return false;
}
void Graham(int n)
{
    point p0;
    int k = 0;
    p0 = List[0];
    for(int i = 1; i < n; i++){
        if(p0.y > List[i].y || (p0.y == List[i].y && p0.x > List[i].x))
        {
            p0 = List[i];
            k = i;
        }
    }
    swap(List[k],List[0]);
    sort(List+1,List+n,_cmp);
    if(n == 1)
    {
        top = 1;
        Stack[0] = 0;
        return;
    }
    if(n == 2)
    {
        top = 2;
        Stack[0] = 0;
        Stack[1] = 1;
        return;
    }
    Stack[0] = 0;
    Stack[1] = 1;
    top = 2;
    for(int i = 2; i < n; i++)
    {
        while(top > 1 &&
                ((List[Stack[top-1]]-List[Stack[top-2]])^(List[i]-List[Stack[top-2]])) <= 0)
            top--;
        Stack[top++] = i;
    }
}
double rotating_calipers(point p[],int n)
{
    double ans = 999999999999999999999.0;
    point v;
    int cur = 1;
    for(int i = 0; i < n; i++)
    {
        v = p[i]-p[(i+1)%n];
        while((v^(p[(cur+1)%n]-p[cur])) < 0){
            cur = (cur+1)%n;s
        }
        Line qw=Line(p[(i)%n],p[(i+1)%n]);
//        point zz=NearestpointToLineSeg(p[cur],qw);
        double as=emmm(p[cur],qw);
        //as=max(as,zx);
        ans=min(ans,as);
//        ans=min(ans,max(dist(p[i],p[cur]),dist(p[(i+1)%n],p[(cur+1)%n])));
    }
    return ans;
}
point p[MAXN];
int main()
{
    int n,r;
    while(~scanf("%d%d",&n,&r))
    {

        for(int i = 0; i < n; i++)List[i].sc();
        Graham(n);
        for(int i = 0; i < top; i++)p[i] = List[Stack[i]];
        printf("%.16f\n",rotating_calipers(p,top));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lalalatianlalu/p/8973980.html