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

Time Limit: 3000MS Memory Limit: 65536K

Description

Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the title 'Miss Cow World'. As a result, Bessie will make a tour of N (2 <= N <= 50,000) farms around the world in order to spread goodwill between farmers and their cows. For simplicity, the world will be represented as a two-dimensional plane, where each farm is located at a pair of integer coordinates (x,y), each having a value in the range -10,000 ... 10,000. No two farms share the same pair of coordinates.

Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms.

Input

* Line 1: A single integer, N

* Lines 2..N+1: Two space-separated integers x and y specifying coordinate of each farm

Output

* Line 1: A single integer that is the squared distance between the pair of farms that are farthest apart from each other. 

Sample Input

4
0 0
0 1
1 1
1 0

Sample Output

2

Hint

Farm 1 (0, 0) and farm 3 (1, 1) have the longest distance (square root of 2) 

题意:

有一头美牛,她要再一个二维平面上,跑遍上面所有的农场(每个农场都有一个坐标,并且农场不重合),她现在想知道任意两个农场中,最大距离的平方是多少?

题解:

一看农场有几座,50000……emmm,看来 $O(n^2)$ 的暴力是肯定跪了的。然后不难发现,两农场间最大距离肯定是出现在凸包边界上的两个点间;

所以我们求出凸包,遍历凸包上的点可以优化时间复杂度。

由于这题时间卡的不紧,那要是数据里面有一个 $50000$ 个点的凸包边界呢?一样要GG。

所以,我们有了一种新的方法叫做旋转卡壳法,具体什么个方法,网上有一张很常见的图:

参考关于旋转卡壳的讲解:https://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html

卡壳的一种情况是这样,两边分别卡着凸包的一条边和一个点。(另一种是同时卡住两个点,这两个点被称为对踵点

这种情况在实现中比较容易处理,这里就只研究这种情况。

在第二种情况中 我们可以看到一个对踵点和对应边之间的距离比其他点要大。

也就是说,一个对踵点和对应边所形成的三角形面积是最大的,据此可以得到对踵点的简化求法。

如果 $q_a,q_b$ 分别是凸包上最远的两点,必然可以分别过 $q_a,q_b$ 画出一对平行线(即卡壳)。

然后通过旋转这对平行线,我们可以让它和凸包上的一条边重合,即图中的直线 $(q_a,p)$,可以注意到,此时 $q_a$ 是凸包上离直线 $(q_a,p)$ 最远的点。

于是我们的思路就是:枚举凸包上的所有边,对每一条边找出凸包上离该边最远的顶点,计算这个顶点到该边两个端点的距离,并记录最大的值。

直观上这是一个 $O(n^2)$ 的算法,和直接枚举任意两个顶点一样。

然而我们可以发现,凸包上的点依次与对应边产生的距离成单峰函数

根据这个凸包的特性,可以注意到,逆时针枚举边的时候,最远点的变化也是逆时针的,这样就可以不用从头计算最远点,而可以紧接着上一次的最远点继续计算。

于是我们得到了 $O(n)$ 的求最远点对的算法:利用旋转卡壳,我们可以在 $O(n)$ 的时间内得到凸包的对踵点中长度最长的点对;又由于最远点对必然属于对踵点对集合,所以用旋转卡壳求出对踵点对集合,然后维护对踵点间最大的距离即可。

代码模板:

double RotatingCalipers(const vector<Point> &ch) //旋转卡壳法
{
double ans=;
int sz=ch.size();
for(int i=,q=;i<sz;i++)
{
int j=(i+)%sz;
while( Cross(ch[j]-ch[i],ch[(q+)%sz]-ch[i]) > Cross(ch[j]-ch[i],ch[q]-ch[i]) ) q=(q+)%sz;
ans=max( ans, max(Length(ch[i],ch[q]),Length(ch[j],ch[q])) );
ans=max( ans, max(Length(ch[i],ch[(q+)%sz]),Length(ch[j],ch[(q+)%sz])) );
}
return ans;
}

其中这么维护最大值的原因是考虑这种情况:

AC代码(在OpenJudge百练2187提交):

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const double eps=1e-;
const double INF=1e18; int Sign(double x)
{
if(x<-eps) return -;
if(x>eps) return ;
return ;
}
int Cmp(double x,double y){return Sign(x-y);} struct Point
{
double x,y;
Point(double _x=,double _y=):x(_x),y(_y){}
Point operator+(const Point &o)const{return Point(x+o.x,y+o.y);}
Point operator-(const Point &o)const{return Point(x-o.x,y-o.y);}
Point operator*(double k)const{return Point(x*k,y*k);}
Point operator/(double k)const{return Point(x/k,y/k);}
int operator==(const Point &o)const{return Cmp(x,o.x)== && Cmp(y,o.y)==;}
bool operator<(const Point &o)const
{
int sgn=Cmp(x,o.x);
if(sgn==-) return ;
else if(sgn==) return ;
else return Cmp(y,o.y)==-;
}
void print(){printf("%.11f %.11f\n",x,y);}
};
typedef Point Vctor; //叉积
double Cross(Vctor A,Vctor B){return A.x*B.y-A.y*B.x;}
double Cross(Point O,Point A,Point B){return Cross(A-O,B-O);} //距离
double Dot(Vctor A,Vctor B){return A.x*B.x+A.y*B.y;}
double Length(Vctor A){return sqrt(Dot(A,A));}
double Length(Point A,Point B){return Length(A-B);} vector<Point> ConvexHull(vector<Point> P,int flag=) //flag=0不严格 flag=1严格
{
if(P.size()<=) return P;
int sz=P.size();
vector<Point> ans(*sz);
sort(P.begin(),P.end());
int now=-;
for(int i=;i<sz;i++)
{
while(now> && Sign(Cross(ans[now]-ans[now-],P[i]-ans[now-]))<flag) now--;
ans[++now]=P[i];
}
int pre=now;
for(int i=sz-;i>=;i--)
{
while(now>pre && Sign(Cross(ans[now]-ans[now-],P[i]-ans[now-]))<flag) now--;
ans[++now]=P[i];
}
ans.resize(now);
return ans;
} double RotatingCalipers(const vector<Point> &P) //旋转卡壳法
{
double ans=;
int sz=P.size();
for(int i=,q=;i<sz;i++)
{
int j=(i+)%sz;
while( Cross(P[j]-P[i],P[q]-P[i]) < Cross(P[j]-P[i],P[(q+)%sz]-P[i]) ) q=(q+)%sz;
ans=max( ans, max(Length(P[i],P[q]),Length(P[j],P[q])) );
ans=max( ans, max(Length(P[i],P[(q+)%sz]),Length(P[j],P[(q+)%sz])) );
}
return ans;
} int n;
vector<Point> P; int main()
{
cin>>n;
for(int i=;i<=n;i++)
{
double x,y; cin>>x>>y;
P.pb(Point(x,y));
}
double ans=RotatingCalipers(ConvexHull(P));
printf("%.0f\n",ans*ans);
}

PS.用jls给的几何板子更新了一下模板,这里求凸包的方法用的是Jarris步进法,时间复杂度 $O(nH)$,其中 $H$ 是凸包边界上的点数。

POJ 2187 - Beauty Contest - [凸包+旋转卡壳法][凸包的直径]的更多相关文章

  1. POJ 2187 Beauty Contest【旋转卡壳求凸包直径】

    链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...

  2. 【POJ】2187 Beauty Contest(旋转卡壳)

    http://poj.org/problem?id=2187 显然直径在凸包上(黑书上有证明).(然后这题让我发现我之前好几次凸包的排序都错了QAQ只排序了x轴.....没有排序y轴.. 然后本题数据 ...

  3. poj 2187:Beauty Contest(计算几何,求凸包,最远点对)

    Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 26180   Accepted: 8081 D ...

  4. poj 2187 Beauty Contest(凸包求解多节点的之间的最大距离)

    /* poj 2187 Beauty Contest 凸包:寻找每两点之间距离的最大值 这个最大值一定是在凸包的边缘上的! 求凸包的算法: Andrew算法! */ #include<iostr ...

  5. poj 2187 Beauty Contest(二维凸包旋转卡壳)

    D - Beauty Contest Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u ...

  6. poj 2187 Beauty Contest , 旋转卡壳求凸包的直径的平方

    旋转卡壳求凸包的直径的平方 板子题 #include<cstdio> #include<vector> #include<cmath> #include<al ...

  7. poj 2187 Beauty Contest (凸包暴力求最远点对+旋转卡壳)

    链接:http://poj.org/problem?id=2187 Description Bessie, Farmer John's prize cow, has just won first pl ...

  8. POJ 2187 Beauty Contest(凸包,旋转卡壳)

    题面 Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the ...

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

    Description Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, ea ...

随机推荐

  1. [C#] 解决Silverlight反射安全关键(SecuritySafeCritical)时报“System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问”的问题

    作者: zyl910 一.缘由 在Silverlight中使用反射动态访问时,经常遇到"System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问-- ...

  2. Docker Mysql数据库主从同步配置方法

    一.背景 最近在做内部平台架构上的部署调整,顺便玩了一下数据库的主从同步,特此记录一下操作- 二.具体操作 1.先建立数据存放目录(-/test/mysql_test/) --mysql --mast ...

  3. Android PopupWindow 仿微信弹出效果

    项目中,我须要PopupWindow的时候特别多,这个东西也特别的好使,所以我今天给大家写一款PopupWindow 仿微信弹出效果.这样大家直接拿到项目里就能够用了! 首先让我们先看效果: 那么我首 ...

  4. 不得不看,只有专家才知道的17个SQL查询提速秘诀!

    不得不看,只有专家才知道的17个SQL查询提速秘诀! 原创 2018-01-23 布加迪编译 51CTO技术栈 “ 除非你遵循本文介绍的这些技巧,否则很容易编写出减慢查询速度或锁死数据库的数据库代码. ...

  5. (8) MySQL主从复制架构使用方法

    一. 单个数据库服务器的缺点 数据库服务器存在单点问题 数据库服务器资源无法满足增长的读写请求 高峰时数据库连接数经常超过上限 二. 如何解决单点问题 增加额外的数据库服务器,组建数据库集群 同一集群 ...

  6. 干货 | Elasticsearch 集群健康值红色终极解决方案【转】

    题记 Elasticsearch当清理缓存( echo 3 > /proc/sys/vm/drop_caches )的时候,出现 如下集群健康值:red,红色预警状态,同时部分分片都成为灰色.  ...

  7. 基于jQuery扁平多颜色选项卡切换代码

    基于jQuery扁平多颜色选项卡切换代码,支持自动轮播切换,鼠标滑过切换的jQuery特效.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class=" ...

  8. Git 子模块 - submodule(转)

    原文地址: http://www.cnblogs.com/kelsen/p/5918672.html 有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目. 也许是第三方库,或者你 独立开 ...

  9. hdoj:2083

    简易版之最短距离 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  10. rabbitmq消费端加入精确控频。

    控制频率之前用的是线程池的数量来控制,很难控制.因为做一键事情,做一万次,并不是每次消耗的时间都相同,所以很难推测出到底多少线程并发才刚好不超过指定的频率. 现在在框架中加入控频功能,即使开200线程 ...