鏈接:https://vjudge.net/problem/POJ-2187
題意:求求距離最遠點對。
思路:肯定爲凸包上的點,可枚舉,也可根據凸包性質旋轉卡殼求對踵點。
參考博客:
https://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html
https://blog.csdn.net/ACMaker/article/details/3177045
旋轉卡殼詳解:https://blog.csdn.net/ACMaker
1.凸包+枚舉 313ms
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 5e4+10;
const double eps = 1e-8;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
struct Point
{
ll x,y;
Point(){}
Point(ll x,ll y):x(x),y(y){}
Point operator -(const Point& b)const//相減
{
return Point(x-b.x,y-b.y);
}
ll operator ^(const Point& b)const//叉乘
{
return x*b.y-y*b.x;
}
ll operator *(const Point& b)const//點乘
{
return x*b.x+y*b.y;
}
}ps[N],st[N];
int n,pos,top;
ll x,ans;
bool cmp(const Point& a,const Point& b)
{
x=(a-ps[1])^(b-ps[1]);
if(x==0)
{
if(a.y==b.y)
return a.x<b.x;
else return a.y<b.y;
}
else if(x>0) return 1;
else return 0;
}
bool check(Point a,Point b,Point c)
{
x=(b-a)^(c-a);
return x<=0;
}
void getconv()
{
top=2;
st[1]=ps[1];
st[2]=ps[2];
for(int i=3;i<=n;i++)
{
while(top>2&&check(st[top-1],st[top],ps[i]))
top--;
st[++top]=ps[i];
}
}
ll dis(Point a,Point b)
{
return (a-b)*(a-b);
}
int main(void)
{
while(~scanf("%d",&n))
{
pos=1;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&ps[i].x,&ps[i].y);
if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
pos=i;
}
swap(ps[1],ps[pos]);
sort(ps+2,ps+n+1,cmp);
getconv();
ans=0;
for(int i=1;i<=top;i++)
for(int j=i+1;j<=top;j++)
ans=max(ans,dis(st[i],st[j]));
printf("%lld\n",ans);
}
return 0;
}
2.凸包+旋轉卡殼
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 5e4+10;
const double eps = 1e-8;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
struct Point
{
ll x,y;
Point(){}
Point(ll x,ll y):x(x),y(y){}
Point operator -(const Point& b)const//相減
{
return Point(x-b.x,y-b.y);
}
ll operator ^(const Point& b)const//叉乘
{
return x*b.y-y*b.x;
}
ll operator *(const Point& b)const//點乘
{
return x*b.x+y*b.y;
}
}ps[N],st[N];
int n,pos,top;
ll x;
bool cmp(const Point& a,const Point& b)
{
x=(a-ps[0])^(b-ps[0]);
if(x==0)
{
if(a.y==b.y)
return a.x<b.x;
else return a.y<b.y;
}
else if(x>0) return 1;
else return 0;
}
bool check(Point a,Point b,Point c)
{
x=(b-a)^(c-a);
return x<=0;
}
void getconv()//求凸包
{
st[0]=ps[0];
st[1]=ps[1];
top=1;
for(int i=2;i<n;i++)
{
//逆時針必須向左轉
while(top>1&&check(st[top-1],st[top],ps[i]))
top--;
st[++top]=ps[i];
}
}
ll dis(Point a,Point b)
{
return (a-b)*(a-b);
}
ll RC()//旋轉卡殼
{
if(top==1) return dis(st[0],st[1]);
ll ans=0;
int j=2;
st[++top]=st[0];
for(int i=0;i<top;i++)
{
//找距離邊最遠的點
while(((st[i]-st[j])^(st[i+1]-st[j]))<((st[i]-st[j+1])^(st[i+1]-st[j+1])))
j=(j+1)%top;
//點對爲其一
ans=max(ans,max(dis(st[i],st[j]),dis(st[i+1],st[j])));
}
return ans;
}
int main(void)
{
while(~scanf("%d",&n))
{
pos=0;
for(int i=0;i<n;i++)
{
scanf("%lld%lld",&ps[i].x,&ps[i].y);
if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
pos=i;
}
swap(ps[0],ps[pos]);
sort(ps+1,ps+n,cmp);
getconv();
printf("%lld\n",RC());
}
return 0;
}