【poj 2187】Beauty Contest(凸包,graham扫描法,旋转卡壳法)

题目链接
题意:给n(<=5e4)个点的坐标(位于同一平面),求最远点对的距离的平方。

分析:求凸包。
凸包定义及其解法:http://blog.csdn.net/yangkunpengd/article/details/51336453
大概有 暴力法,分治法,步进法,graham扫描法等。
常用graham扫描法。
旋转卡壳法: 可以用来求凸包的直径(即最远的两点间的距离)

挑战程序设计P261-263
AC代码:

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

#define mem(a,n) memset(a,n,sizeof(a))
#define memc(a,b) memcpy(a,b,sizeof(b))
#define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n)
#define dec(i,n,a) for(int i=n;i>=a;i--)///[n,a]
#define pb push_back
#define fi first
#define se second
#define IO ios::sync_with_stdio(false)
#define fre freopen("in.txt","r",stdin)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
typedef unsigned long long ull;
const double PI=acos(-1.0);
const double E=2.718281828459045;
const double eps=1e-3;
const int INF=0x3f3f3f3f;
const int MOD=258280327;
const int N=5e4+5;
const ll maxn=1e6+5;
const int dir[4][2]= {-1,0,1,0,0,-1,0,1};
struct point
{
    double x,y;
    point() {}
    point(double x,double y):x(x),y(y) {}
    point operator + (point p)
    {
        return point(x+p.x,y+p.y);
    }
    point operator - (point p)
    {
        return point(x-p.x,y-p.y);
    }
    point operator * (double d)
    {
        return point(x*d,y*d);
    }
    ///点乘
    double dot(point p)
    {
        return x*p.x+y*p.y;
    }
    ///叉乘
    double det(point p)
    {
        return x*p.y-y*p.x;
    }
    bool operator < (const point& m)const
    {
        if(x!=m.x)
            return x<m.x;
        return y<m.y;
    }
};
bool cmp(const point& a,const point& b)
{
    if(a.x!=b.x) return a.x<b.x;
    return a.y<b.y;
}
///求凸包  graham扫描法
vector<point> convex_hull(point *a,int tot)
{
    sort(a,a+tot);
    vector<point>p(tot*2); ///构造中的凸包
    int k=0;///凸包的顶点数
    ///构造凸包的下侧
    for(int i=0; i<tot; i++)
    {
        while(k>1&&(p[k-1]-p[k-2]).det(a[i]-p[k-1])<=0)
            k--;
        p[k++]=a[i];
    }
    int t=k;
    ///构造凸包的上侧
    for(int i=tot-2; i>=0; i--)
    {
        while(k>t&&(p[k-1]-p[k-2]).det(a[i]-p[k-1])<=0)
            k--;
        p[k++]=a[i];
    }
    p.resize(k-1);
    return p;
}
///距离的平方
double dis(point p,point q)
{
    return (p-q).dot(p-q);
}
point a[N];
int n;
void solve()
{
    vector<point> p = convex_hull(a, N);
    int n = p.size();
    if (n == 2)          ///特别处理凸包退化的情况
    {
        printf("%.0f\n", dis(p[0], p[1]));
        return;
    }
    int i = 0, j = 0;           ///某个方向上的对踵点对
    ///求出x轴方向上的对踵点对
    for (int k = 0; k < n; k++)
    {
        if (!cmp(p[i], p[k]))
            i = k;
        if (cmp(p[j], p[k]))
            j = k;
    }
    double res = 0;
    int si = i, sj = j;
    while (i != sj || j != si)      ///将方向逐步旋转180度
    {
        res = max(res, dis(p[i], p[j]));
        ///判断先转到边i-(i+1)的法线方向还是边j-(j+1)的法线方向
        if ((p[(i + 1) % n] - p[i]).det(p[(j + 1) % n] - p[j]) < 0)
            i = (i + 1) % n;        ///先转到边i-(i+1)的法线方向
        else
            j = (j + 1) % n;        ///先转到边j-(j+1)的法线方向
    }
    printf("%.0f\n", res);
}
int main()
{
    scanf("%d",&n);
    for(int i=0; i<n; i++)
        scanf("%lf%lf",&a[i].x,&a[i].y);
    solve();
    return 0;
}

另外:较为清晰和简洁的写法:
http://hzwer.com/4224.html
http://www.cppblog.com/staryjy/archive/2009/11/19/101412.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值