题目链接
题意:给n(<=5e4)个点的坐标(位于同一平面),求最远点对的距离的平方。
分析:求凸包。
凸包定义及其解法:http://blog.youkuaiyun.com/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