graham's scan 求凸包:
先将所有点根据x,y按字典序排序,显然字典序最小的和最大的都是凸包上的点,字典序最小的是凸包中左下角的点,字典序最大的是凸包上右上角的点。(设字典序最小的点为A,如下图第0个点,字典序最大的点为B,如下图第6个点)
那么整个凸包就被A、B分成了两条链,A->B,B->A。那么就只要分别从A和B开始不断增加点得到这两条链就可以了。由于graham's scan是逆时针求凸包的,而凸包上的点所连出的线段的斜率在逆时针方向都是不断变大的,所以在求上下链的时候,如果新增加的这个点使斜率减小那么就会出现凹进去的情况,那么舍掉这个点就可以了。
模板题:Beauty Contest
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct P
{
int x,y;
bool operator <(P t)const
{
if(x==t.x)return y<t.y;
else return x<t.x;
}
P operator -(P t)
{
return (P){x-t.x,y-t.y};
}
int det(P t)//用来判断两条线段的斜率是递增还是递减
{
return x*t.y-y*t.x;
}
int dot(P t)
{
return x*t.x+y*t.y;
}
};
const int M=5e4+20;
int k,n;
P s[M],c[M];
void get_c()//求凸包
{
k=0;
sort(s,s+n);
for(int i=0;i<n;i++)//增加新点,求下面的链,A->B
{
while(k>1&&(c[k-1]-c[k-2]).det(s[i]-c[k-1])<=0)k--;//保证所有线段的斜率是递增的
c[k++]=s[i];
}
for(int i=n-2,t=k;i>=0;i--)//求上面的链,B->A
{
while(k>t&&(c[k-1]-c[k-2]).det(s[i]-c[k-1])<=0)k--;
c[k++]=s[i];
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&s[i].x,&s[i].y);
}
get_c();
int ans=0;
for(int i=0;i<k;i++)
{
for(int j=0;j<k;j++)
if(i!=j)
ans=max(ans,(c[i]-c[j]).dot(c[i]-c[j]));
}
printf("%d\n",ans);
return 0;
}