题意:给你n个点,选四个点构成四边形,求四边形的面积最大最小值的两倍。
分析:先将点按照x为第一关键词y为第二关键词从小到大排序,然后我们开始取向量,并将所取的所有向量进行极角排序。第一条向量的两个端点在之前排序过的点的序列中是相邻的。这样的序列保证在序列的第一个点到向量的左端点的点距离这条直线单调递减,右侧也一样,那么我们考虑当我们旋转坐标系的时候,画图可知,受影响的点只有之前那条向量上的点,而且根据之前矛盾关系,之前那条的斜率大于现在这条,那么之前那条的两端点到这条线上的距离一个小一个大,那么我们只需要更换这两个点在序列中的位置,即可满足之前的单调性,所以每次旋转坐标系只需要交换上一条的向量两端点在排序后的序列中的位置即可,这样我们就维护出了距离对角线最远和最近的点,最大最小四边形面积也可以得出,也可以用此方法求得最大最小三角形面积。
参考博客:https://www.cnblogs.com/dd-bond/p/10924059.html
同样的题还有BZOJ3707、CodeForces - 1019D
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e6+10;
int p[2010];
struct Point{
int x,y,i,j;
Point(){ x=y=0; }
Point(int a,int b){ x=a,y=b; }
Point(int a,int b,Point p){ i=a,j=b,x=p.x,y=p.y; }
Point operator -(const Point &n)const{ return Point(x-n.x,y-n.y); }
bool operator <(const Point&n)const{ return x==n.x? y<n.y: x<n.x; }
}point[2010],vec[2*MAXN];
ll cross(Point a,Point b){ return 1ll*a.x*b.y-1ll*a.y*b.x; }
ll check(int i,int j,int k){ return abs(cross(point[j]-point[i],point[k]-point[i])); }
int main(void)
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
ll n;
while(cin>>n){
ll s1=9e18,s2=0,cnt=0;
for(int i=0;i<n;i++) cin>>point[i].x>>point[i].y,p[i]=i;
if(n<4) return cout<<0<<' '<<0<<endl,0;
sort(point,point+n);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
vec[cnt++]=Point(i,j,point[j]-point[i]);
sort(vec,vec+cnt,[](Point a,Point b){ return cross(a,b)>0; });
for(int i=0;i<cnt;i++){
int a=vec[i].i,b=vec[i].j;
///if(p[a]>p[b]) swap(a,b);
if(p[a]!=0&&p[b]!=n-1) s2=max(s2,check(p[a],p[b],0)+check(p[a],p[b],n-1));
if(p[a]!=0&&p[b]!=n-1) s1=min(s1,check(p[a],p[b],p[a]-1)+check(p[a],p[b],p[b]+1));
///交换
swap(p[a],p[b]); swap(point[p[a]],point[p[b]]);
}
cout<<s1<<' '<<s2<<endl;
}
return 0;
}