POJ 2187 Beauty Contest(凸包+旋转卡壳)

来源:互联网 发布:免费期货行情软件下载 编辑:程序博客网 时间:2024/05/16 18:18

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

题目:求出凸包的最大直径。

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

先对多边形求凸包,以前的知识不多说。

然后用旋转卡壳求出最大直径。

其实就是两条平行线夹出凸包,旋转。

如果pa,pb为最远点对的话,那么过pa,pb的平行线经过旋转,肯定有一条与多边形的边重合。

利用这点,枚举每一条边,找到离边最远的点,看上去这还是N^2的,和枚举一样。

不过由于是凸多边形,对于某一条边,点到边的距离呈现单峰函数。

那么就可以利用上一条边的最远点依次后移得到。

这篇说得不错:http://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html

#include<iostream>#include<fstream>#include<iomanip>#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<cmath>#include<set>#include<map>#include<queue>#include<stack>#include<string>#include<vector>#include<sstream>#include<ctime>#include<cassert>#define LL long long#define eps 1e-8#define inf 999999.0#define zero(a) abs(a)<eps#define N 20#define pi acos(-1.0)using namespace std;struct Point{    int x,y;}p[50005];int n;vector<Point >s;int dist(Point p1,Point p2){    return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);}int xmul(Point p0,Point p1,Point p2){    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}//Graham_scan求凸包bool cmp(Point p1,Point p2){    if(xmul(p[0],p1,p2)>eps)  return true;    else if(zero(xmul(p[0],p2,p1))&&dist(p[0],p1)<dist(p[0],p2))  return true;    return false;}void Graham_scan(){    for(int i=1;i<n;i++)        if(p[i].y<p[0].y||(p[i].y==p[0].y&&p[i].x<p[0].x))            swap(p[i],p[0]);    sort(p+1,p+n,cmp);    s.clear();    s.push_back(p[0]);s.push_back(p[1]);    for(int i=2;i<n;i++){        while(s.size()>=2&&xmul(s[s.size()-2],s[s.size()-1],p[i])<eps) s.pop_back();        s.push_back(p[i]);    }}//旋转卡壳求凸包直径void Rotating_Calipers(){    int ans=0,len=s.size();    int j=1;    s.push_back(s[0]);    for(int i=0;i<len;i++){        //找到离直线最远的点        while(abs(xmul(s[i],s[i+1],s[j+1]))>abs(xmul(s[i],s[i+1],s[j])))            j=(j+1)%len;        ans=max(ans,max(dist(s[i+1],s[j]),dist(s[i],s[j])));    }    printf("%d\n",ans);}int main(){    while(scanf("%d",&n)!=EOF){        for(int i=0;i<n;i++)            scanf("%d%d",&p[i].x,&p[i].y);        Graham_scan();        Rotating_Calipers();    }    return 0;}