您的位置:首页 > 其它

POJ 2187 旋转卡壳求凸包的直径

2016-07-26 21:09 603 查看
首先推荐一个详细讲解旋转卡壳的博客  http://blog.csdn.net/acmaker
这个博客里面涵盖了大部分常用的旋转卡壳问题。

首先这个题目大概是说给你N个点(N<50000),求解两点间的最大距离。首先如果枚举每一个点,O(n^2),显然是会超时的,那么这边运用旋转卡壳算法能在O(n)时间内算出,单求凸包时排序花费O(nlogn),所以复杂度是O(nlogn)+O(n)。讲道理,这题如果按照分治的思想应该也能跑过。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;

#define MAX_N 50010
#define M_PI 3.14159265358979323846

typedef int type_xy;
struct P
{
type_xy x, y;
P() {}
P(type_xy x, type_xy y) : x(x), y(y) {}
P operator + (P p){ return P(x + p.x, y + p.y); }
P operator - (P p){ return P(x - p.x, y - p.y); }
P operator * (type_xy d){ return P(x*d, y*d); }
bool operator < (const P& a) const
{
if (x != a.x) return x < a.x;
else return y < a.y;
}
type_xy dot(P p) { return x*p.x + y*p.y; }
type_xy det(P p) { return x*p.y - y*p.x; }
};

// 字典序比较
bool cmp_x(P a, P b)
{
if (a.x != b.x) return a.x < b.x;
return a.y < b.y;
}
// 求凸包
vector<P> convex_hull(P *ps, int n)
{
sort(ps, ps + n, cmp_x);
int k = 0;	// 凸包的顶点数
vector<P> qs(n * 2);	// 构造中的凸包
// 构造凸包的下侧
for (int i = 0; i < n; ++i)
{
while (k > 1 && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k;
qs[k++] = ps[i];
}
// 构造凸包的上侧
for (int i = n - 2, t = k; i >= 0; --i)
{
while (k > t && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k;
qs[k++] = ps[i];
}
qs.resize(k - 1);
return qs;
}

// 距离的平方
double dist(P p, P q)
{
return sqrt((double)(p - q).dot(p - q));
}

// 求解凸包对踵点最大距离
double max_distance(P *ps, int N)
{
vector<P> qs = convex_hull(ps, N);
int n = qs.size();
if (n == 2)
{
return dist(qs[0], qs[1]);	// 特别处理凸包退化的情况
}
int i = 0, j = 0;	// 某个方向上的对踵点对
// 求出x轴方向上的对踵点对
for (int k = 0; k < n; k++)
{
if (!cmp_x(qs[i], qs[k])) i = k;
if (cmp_x(qs[j], qs[k])) j = k;
}
double res = 0;
int si = i, sj = j;
while (i != sj || j != si)	// 将方向逐步旋转180度
{
res = max(res, dist(qs[i], qs[j]));
// 判断先转到边i-(i+1)的法线方向还是边j-(j+1)的法线方向
if ((qs[(i + 1) % n] - qs[i]).det(qs[(j + 1) % n] - qs[j]) < 0)
{
i = (i + 1) % n;	//  先转到边i-(i+1)的法线方向
}
else
{
j = (j + 1) % n;	// 先转到边j-(j+1)的法线方向
}
}
return res;
}

P ps[MAX_N];

int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
scanf("%d%d",&ps[i].x,&ps[i].y);
}
double x=max_distance(ps,n);
printf("%d\n",(int)(x*x));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: