凸包扫描 + 旋转卡壳 UVALive 4728

      题意:给n个正方形,求正方形的顶点之间的最大距离。

思路:可以确定的是最远距离的2个点一定在这些正方形的顶点的凸包上的2个点。所以先求一次凸包。 求凸包上2个点的最打距离,实际就是就凸包的直径,有成型的算法。可以用旋转卡壳直接求解。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mod=99999997;
const int mmax=200010;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3fffffff;
#define debug
#define mmax 200010
//typedef __int64 LL;
int sgn(double x)
{
    if(fabs(x)<eps)
        return 0;
    return x>0?1:-1;

}
struct Point
{
    int x,y;
    Point(int x=0,int y=0): x(x),y(y) {}
    void read()
    {
        scanf("%d %d",&x,&y);
    }
};
bool operator < (const Point &a,const Point &b)
{
    return a.x<b.x || (a.x==b.x&&a.y<b.y);
}
bool operator == (const Point &a,const Point &b)
{
    return a.x-b.x==0 && a.y-b.y==0;
}
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double k)
{
    return Vector(A.x/k,A.y/k);
}
Vector operator / (Vector A,double k)
{
    return Vector(A.x/k,A.y/k);
}
int Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
int Length(Vector A)
{
    return Dot(A,A);
}
int Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
int ConvexHull(Point *p,int n,Point *Poly)
{
    sort(p,p+n);
    n=unique(p,p+n)-p;
    int m=0;
    for(int i=0;i<n;i++)
    {
        while(m>1 && Cross(Poly[m-1]-Poly[m-2],p[i]-Poly[m-2])<=0) m--;
        Poly[m++]=p[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k && Cross(Poly[m-1]-Poly[m-2],p[i]-Poly[m-2]) <=0 ) m--;
        Poly[m++]=p[i];
    }
    if(n>1) m--;
    return m;
}
double Angle(Vector v)
{
    double ang=atan2(v.y,v.x);
    while(ang<0)
        ang+=2.0*pi;
    return ang;
}

//旋转卡壳
int RotateStuck(int m,Point * Poly)
{
    int i=0,j=0;
    double angi=0.0,angj=pi;
    for(int k=0;k<m;k++)
    {
        if(Poly[k].y<Poly[i].y)
            i=k;
        if(Poly[k].y>Poly[j].y)
            j=k;
    }
    int m_dis=Length(Poly[i]-Poly[j]);
    int cnt=0;
    while(sgn(angi-pi)<=0)
    {

        double dangi=Angle(Poly[(i+1)%m]-Poly[i])-angi;
        double dangj=Angle(Poly[(j+1)%m]-Poly[j])-angj;
        if(dangi<0)
            dangi+=2.0*pi;
        if(dangj<0)
            dangj+=2.0*pi;
        if(sgn(dangi-dangj)==0)
        {
            m_dis=max(m_dis,Length(Poly[(i+1)%m]-Poly[(j+1)%m]));
            m_dis=max(m_dis,Length(Poly[(i+1)%m]-Poly[j]));
            m_dis=max(m_dis,Length(Poly[i]-Poly[(j+1)%m]));
            i++,j++;
            i%=m,j%=m;
            angi+=dangi;
            angj+=dangi;
        }
        else if(sgn(dangi-dangj)<0)
        {
            i++;
            i%=m;
            m_dis=max(m_dis,Length(Poly[i]-Poly[j]));
            angi+=dangi;
            angj+=dangi;
        }
        else if(sgn(dangi-dangj)>0)
        {
            j++;
            j%=m;
            m_dis=max(m_dis,Length(Poly[i]-Poly[j]));
            angi+=dangj;
            angj+=dangj;
        }
    }
    return m_dis;
}
Point p[400010],Poly[400010];
int main()
{
    int n,t;
    int x,y,r;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<n;i++)
        {
            scanf("%d %d %d",&x,&y,&r);
            p[i]=Point(x+r,y);
            p[i+n]=Point(x,y+r);
            p[i+2*n]=Point(x,y);
            p[i+3*n]=Point(x+r,y+r);
        }
        int m=ConvexHull(p,4*n,Poly);
        printf("%d\n",RotateStuck(m,Poly));
    }
    return 0;
}


你可能感兴趣的:(ACM,uva,计算几何,旋转卡壳)