POJ 2187 Beauty Contest 旋转卡壳

http://poj.org/problem?id=2187

旋转卡壳的思想并不难,你就想象是两个平行直线夹住凸包...求的就是夹住的两个对锺点...

这题更容易了...求出所有对锺点以后直接一遍扫过去求最大点距就行了...

用的是一个结论: s[i],s[i+1],s[q] 构成的三角形只要面积最大<s[i],s[q]> 和 <s[i+1],s[q]>就一定是对锺点对

接下来根据观察...按逆时针枚举所有边的时候q的位置一定是逆时针移动...所以我们根据上一点q的位置逆时针枚举点即可...

找凸包O(nlogn) , 第一遍找q O(n) , 之后旋转操作 O(n) , 总共的复杂度O(nlogn)

提醒一下这题很坑...必须处理 只有2个点,共线,共点的情况,如果是用一般的凸包模板肯定WA...稍微修改一下就行...

 

复制代码
/********************* Template ************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

#define EPS         1e-8
#define MAXN        100005
#define MOD         (int)1e9+7
#define PI          acos(-1.0)
#define INF         ((1LL)<<50)
#define max(a,b)    ((a) > (b) ? (a) : (b))
#define min(a,b)    ((a) < (b) ? (a) : (b))
#define max3(a,b,c) (max(max(a,b),c))
#define min3(a,b,c) (min(min(a,b),c))
#define BUG         cout<<"BUG! "<<endl
#define LINE        cout<<"------------------"<<endl
#define L(t)        (t << 1)
#define R(t)        (t << 1 | 1)
#define Mid(a,b)    ((a + b) >> 1)
#define lowbit(a)   (a & -a)
#define FIN         freopen("in.txt","r",stdin)
#pragma comment     (linker,"/STACK:102400000,102400000")

// typedef long long LL;
// typedef unsigned long long ULL;
// typedef __int64 LL;
// typedef unisigned __int64 ULL;
// int gcd(int a,int b){ return b?gcd(b,a%b):a; }
// int lcm(int a,int b){ return a*b/gcd(a,b); }

/*********************   F   ************************/
struct POINT{
    double x,y;
    POINT(double _x = 0, double _y = 0):x(_x),y(_y){};
};
POINT p[MAXN],s[MAXN];
double dist(POINT p1,POINT p2){
    return((p1.x-p2.x) * (p1.x-p2.x) + (p1.y-p2.y) * (p1.y-p2.y));
}
double multiply(POINT sp,POINT ep,POINT op){
    return (sp.x-op.x) * (ep.y-op.y) - (ep.x-op.x) * (sp.y-op.y);
}
bool ptcmp(POINT a,POINT b){    // 极角排序cmp p[]为全局变量
    if(multiply(a,b,p[0]) == 0) return dist(p[0],a) < dist(p[0],b);
    return (multiply(a,b,p[0]) > 0);
}
int Graham_scan(POINT p[],POINT s[],int n){ //  返回凸包点的个数(修改版处理共线,无凸包)
    int i,k = 0,top = 2;
    for(i = 1; i < n ; i++)     //  取y最小且x最小的点为凸包起点
        if((p[i].y < p[k].y) || ((p[i].y == p[k].y) && (p[i].x < p[k].x)))
            k = i;
    swap(p[0],p[k]);            //  起点设置为p[0]
    if(n == 2) {                //  只有两个点不构成凸包的特判
        s[0] = p[0];
        s[1] = p[1];
        return 2;
    }
    sort(p+1,p+n,ptcmp);        //  极角排序
    for(i = 0 ; i < 3 ; i++)
        s[i] = p[i];            //  前三个点入栈
    while(multiply(s[0],s[top],s[top-1]) == 0 && i < n){ // 前三个点的共线特判
        s[top-1] = s[top];
        s[top] = p[i++];
    }
    if(i == n){                 //所有点都共线的特判
        s[1] = s[top];
        return 2;
    }
    for(; i < n ; i++){
        while(multiply(p[i],s[top],s[top-1]) >= 0)
            top--;
        s[++top] = p[i];
    }
    return top + 1;
}
double Triangle_area(POINT a,POINT b,POINT c){
    return fabs(multiply(a,b,c)/2);
}
double Rotation_Calipers(int len){      //旋转卡壳求凸包最大点距
    double ans = 0;
    for(int i = 0 ,q = 1; i < len ; i++){
        while(Triangle_area(s[i],s[(i+1)%len],s[(q+1)%len])
              > Triangle_area(s[i],s[(i+1)%len],s[q])){
              q = (q + 1) % len;
        }
        ans = max3(ans,dist(s[q],s[i]),dist(s[q],s[(i+1)%len]));
    }
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("ou.txt","w",stdout);
    int a,b,n;
    double r;
    while(~scanf("%d",&n)){
        for(int i = 0 ; i < n ; i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        int len = Graham_scan(p,s,n);
        double ans = Rotation_Calipers(len);
        printf("%.0lf\n",ans);
    }
    return 0;
}
复制代码

 

posted @   Felix_F  阅读(241)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示