最远对踵点 旋转卡壳

original link - http://poj.org/problem?id=2187

题意:

求最远点对

推荐 https://blog.csdn.net/wang_heng199/article/details/74477738

解析:

对踵点定义:多边形的两个位于平行切线上的点。

最远对踵点 旋转卡壳_第1张图片

最远对踵点 旋转卡壳_第2张图片

我们可以通过旋转卡壳 O ( n ) O(n) O(n)得出所有点对应的对踵点。(先处理凸包)


旋转卡壳

当我们顺时针枚举点的时候,这些点的对踵点应该也是顺时针的,所以我们以此枚举即可。

显然对踵点到这条边的距离最长,也就是说形成的三角形面积最大,所以我们可以用叉积来判断对踵点。

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=5e4+9;
const double eps=1e-7;
struct point{
    double x,y;
    point(double x=0,double y=0):x(x),y(y){}
};
typedef point P;
typedef point Point;
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 p){//向量数乘
    return Vector(a.x*p, a.y*p);
}
Vector operator / (Vector a, double p){//向量数除
    return Vector(a.x / p, a.y / p);
}
int dcmp(double x){//精度三态函数(>0,<0,=0)
    if (fabs(x) < eps)return 0;
    else if (x > 0)return 1;
    return -1;
}
bool operator == (const Point &a, const Point &b){//向量相等
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Cross(P a,P b){ // 叉积 平行四边形面积
    return (a.x*b.y)-(b.x*a.y);
}
double LengthPow(Vector v){
    return v.x*v.x+v.y*v.y;
}
double Distance(P a,P b){
    return sqrt(LengthPow(a-b));
}

point p[maxn],ans[maxn];
int n,top;
point Tmp;//选好的起点
bool cmp(point a,point b){
    double ans=Cross(a-Tmp,b-Tmp);
    if(dcmp(ans)==0)return dcmp(Distance(a,Tmp)-Distance(b,Tmp))<0;
    return ans>0;//表示a到b是逆时针转
}
// 去掉共线点
void Graham(point p[],int n,point ans[],int &top){
    if(n<3){
        for(int i=1;i<=n;i++)ans[i]=p[i];
        top=n;
        return;
    }
    for(int i=2;i<=n;i++){
        if(p[i].y<p[1].y||(dcmp(p[i].y-p[1].y)==0&&p[i].x<p[1].x))
            swap(p[1],p[i]);
    }
    Tmp=p[1];
    sort(p+2,p+1+n,cmp);
    ans[1]=p[1],ans[2]=p[2],top=2;
    for(int i=3;i<=n;i++){
        while(top>2&&dcmp(Cross(ans[top]-ans[top-1],p[i]-ans[top]))<=0)top--;
        ans[++top]=p[i];
        if(top>2&&dcmp(Cross(ans[top]-ans[top-1],ans[top-1]-ans[top-2]))==0)ans[top-1]=ans[top],--top;
    }
}

#define rep(i,a,b) for(int i=a;i<=b;i++)

double RotateCalipers(P *p,int n){
    if(n==2)return LengthPow(p[1]-p[2]);
    double ans=-1;
    p[n+1]=p[1];
    // 保证q在i的前面,使得∠q_i+1_i小于180度
    int q=2;
    rep(i,1,n){// 枚举边i~i+1 , 如果q+1优于q , 旋转
        while(Cross(p[q]-p[i+1],p[i]-p[i+1])<Cross(p[q+1]-p[i+1],p[i]-p[i+1]))q=q%n+1;
        ans=max(ans,max(LengthPow(p[q]-p[i]),LengthPow(p[q+1]-p[i+1])));
    }
    return ans;
}

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        rep(i,1,n){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        Graham(p,n,ans,top);
        printf("%.0f\n",round(RotateCalipers(ans,top)));
    }
}

你可能感兴趣的:(平面几何)