现在的位置: 首页 > 综合 > 正文

POJ 2187 Beauty Contest(旋转卡壳求点凸包直径)

2013年09月03日 ⁄ 综合 ⁄ 共 2442字 ⁄ 字号 评论关闭

题目链接:http://poj.org/problem?id=2187

这个题目做过,不过上次是直接枚举的结果,这次换一种方法,旋转卡壳来计算凸包直径,这个方法比以前的要快好多

主要思想就是用两条平行线来夹住凸包,那么不断旋转这两条平行线,可想而知凸包的直径一定就是两条平行线和凸包

顶点的交点的长度,这时候再枚举就可以了!

具体解说推荐一篇博客:http://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html

这个图片就是那篇博客上的图片,可以很好的解说下面的卡壳部分的代码

for(i=0;i<k;i++)
{
    while(across(po[i],po[i+1],po[q]) < across(po[i],po[i+1],po[q+1]))
          q=(q+1)%k;
    ans=MAX(ans,MAX(dis(po[i],po[q]),dis(po[i+1],po[q+1])));
}

就是这一点代码,其实还是很好理解的,按照相当于按照逆时针旋转卡壳,这里是按照一条边对应一个点来的,所以这里枚举的时候

是一条边和一个点,通过凸包的面积单调性来求对踵点

有读者可能会认为上面的算法不是线性的,其实是线性的,即使里面有个while循环,但是这个循环不会绕凸包两圈以上的

因为下一次的对踵点一定是在上一个之后,所以就在原来的基础上去找就OK 了,其实仔细想想还是比较好理解的!

其实下面的代码是求多边形的长,直径,那么取的是对踵点之间的最长距离,如果是求宽度,那么就是求多边形的

对踵点之间的最小距离,那么直接把下面的函数MAX改成MIN就OK 了,因为最大和最小都一定是产生在对踵点之

间的!

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
#define eps 1e-8
#define PI 3.14159265
#define MAX(a,b) (a>b?a:b)
struct point
{
int x;
int y;
}po[55500],temp;
int n,pos;
bool zero(double a)
{
return fabs(a) < eps;
}
int dis(point &a,point &b)//返回两点之间距离的平方
{
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
int across(point &a,point &b,point &c)//求a b and a c 的X积
{
return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}
int cmp(const void *a,const void *b)
{
return across(po[0],*(point*)a,*(point*)b) > 0 ? -1 : 1;
}
int select()
{
int i,j,k=1;
for(i=2;i<n;i++)
{
if(across(po[0],po[k],po[i])==0)
{
if(dis(po[0],po[k]) < dis(po[0],po[i]))
po[k]=po[i];
}
else
po[++k]=po[i];
}
return k+1;
}
int graham(int num)
{
int i,j,k=2;
//////////////////////////////////////////
po[num]=po[0];//fangbian
num++;
int p,q;
int ans=0;
int t;
if(num<20)
{
for(i=0;i<num;i++)
for(j=0;j<num;j++)
{
t=dis(po[i],po[j]);
if(t > ans)
ans=t;
}
printf("%d\n",ans);
return 0;
}
for(i=3;i<num;i++)
{
while(across(po[k-1],po[k],po[i]) < -eps)
{k--;}
po[++k]=po[i];//就这个循环结束,不需要了!
}
/*
for(i=0;i<k;i++)
printf("%lf %lf\n",po[i].x,po[i].y);
*/
//for(i=0;i<k;i++)
//for(j=0;j<k;j++)
//{
//t=dis(po[i],po[j]);
//if(t > ans)
//ans=t;
//}
ans=0;
p=1,q=2;
for(i=0;i<k;i++)
{
    while(across(po[i],po[i+1],po[q]) < across(po[i],po[i+1],po[q+1]))
          q=(q+1)%k;
    ans=MAX(ans,MAX(dis(po[i],po[q]),dis(po[i+1],po[q+1])));
}
printf("%d\n",ans);
return 0;
}
int main()
{
int i,j,k;
point my_temp;
int ans;
int t;
while(scanf("%d",&n)!=EOF)
{
ans=0;
scanf("%d%d",&po[0].x,&po[0].y);
temp=po[0];
pos=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&po[i].x,&po[i].y);
if(po[i].y < temp.y)
temp=po[i],pos=i;
}
if(n<100)
{
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
t=dis(po[i],po[j]);
if(t > ans)
ans=t;
}
printf("%d\n",ans);
continue;
}

my_temp=po[0];
po[0]=po[pos];
po[pos]=my_temp;
qsort(po+1,n-1,sizeof(po[0]),cmp);
graham(select());
}
return 0;
}

抱歉!评论已关闭.