题目描述
Given n distinct points on a plane, your task is to find the triangle that have the maximum area, whose vertices are from the given points.
Input
The input consists of several test cases. The first line of each test case contains an integer n, indicating the number of points on the plane. Each of the following n lines contains two integer xi and yi, indicating the ith points. The last line of the input is an integer −1, indicating the end of input, which should not be processed. You may assume that 1 <= n <= 50000 and −104 <= xi, yi <= 104 for all i = 1 … n.
Output
For each test case, print a line containing the maximum area, which contains two digits after the decimal point. You may assume that there is always an answer which is greater than zero.
Sample Input
3
3 4
2 6
2 7
5
2 6
3 9
2 0
8 0
6 5
-1
Sample Output
0.50
27.00
题解
这道题目的意思就是给你一个点集,在其中选三个点,要你求出选出三个点所围成面积的最大值。
首先我们可以想到,这三个点肯定在点集的凸包上,不然的话就可以往外扩展使得面积更大。
那么怎么在凸包上求呢?
我们可以在凸包上枚举一个端点i,然后我们在利用凸包的单峰去找到那两个点。那么我们怎么从i个点转到第i+1个点呢?
我们可以发现,既然我们枚举端点是逆时针枚举的,那么在第i个点的答案指针前的那些点,在第i+1个点的时候它的答案肯定是没有答案指针优的,这个画图就可以画得出来,于是我们就可以继承第i个点的答案指针继续向逆时针方向枚举。两个指针都是这样的话,我们就可以把复杂度降到O(n)O(n),比暴力枚举的O(n3)O(n3)要快了不止一点。
这道题目就讲完了,大家如果有不清楚的可以看我代码。
下面放上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 50010
using namespace std;
struct P{
double x,y;
}p[maxn];
int n;
P operator - (P a,P b)
{
P tmp;
tmp.x=a.x-b.x;tmp.y=a.y-b.y;
return tmp;
}
double operator * (P a,P b)
{
return a.x*b.y-b.x*a.y;
}
double dist(P a,P b)
{
P tmp=a-b;
return sqrt(tmp.x*tmp.x+tmp.y*tmp.y);
}
bool cmp(P p1,P p2)
{
double s=(p1-p[1])*(p2-p[1]);
return s>0||(s==0&&dist(p1,p[1])>=dist(p2,p[1]));
}
int q[maxn],top;
bool judge(int p0,int p1,int p2)
{
double s=(p[p1]-p[p0])*(p[p2]-p[p0]);
return s>0||(s==0&&dist(p[p1],p[p0])>=dist(p[p2],p[p0]));
}
double S(P p1,P p2,P p3)
{
double l1=dist(p1,p2),l2=dist(p2,p3),l3=dist(p3,p1);
double ar=(l1+l2+l3)/2;
return sqrt(ar*(ar-l1)*(ar-l2)*(ar-l3));
}
int main()
{
while(~scanf("%d",&n)&&n!=-1)
{
memset(q,0,sizeof(q));
top=0;
for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
int fir=1;
for(int i=2;i<=n;i++)
{
if(p[i].y<p[fir].y||(p[i].y==p[fir].y&&p[i].x<p[fir].x)){
fir=i;
}
}
swap(p[fir],p[1]);
sort(p+2,p+n+1,cmp);
p[n+1]=p[1];
q[++top]=1;q[++top]=2;
for(int i=3;i<=n+1;i++)
{
while(top>1&&judge(q[top-1],i,q[top])==true) top--;
q[++top]=i;
}
int k=2,l=3;
double ans=0.0;//k,l分别是两个指针
for(int i=1;i<top;i++)
{
while((p[q[k]]-p[q[i]])*(p[q[l]]-p[q[i]])<(p[q[k]]-p[q[i]])*(p[q[l+1]]-p[q[i]]))//判断答案大小
{
l++;
if(l==top) l=1;
}
while((p[q[k]]-p[q[i]])*(p[q[l]]-p[q[i]])<(p[q[k+1]]-p[q[i]])*(p[q[l]]-p[q[i]]))//同上
{
k++;
if(k==top) k=1;
}
ans=max(ans,S(p[q[i]],p[q[k]],p[q[l]]));//修改答案
}
printf("%.2lf\n",ans);
}
return 0;
}
谢谢大家!!