给定平面上100个点 求一个最大的凸包,使得它不包含其中任意点,且凸包的顶点是题目所给的点。
枚举凸包左下角的点,顺时针枚举第二个点, 用opt[i][j]记录 i作为第二个点, 且第三个点k在向量i->j的右手(保持凸性)
显然相邻的凸包可以用来转移, opt[j][h]可以加入opt[i][j] 大致思想就是这样 看Solve函数。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100;
const double zero=1e-8;
struct Vector
{
double x,y;
};
inline Vector operator -(Vector a,Vector b)
{
Vector c;
c.x=a.x-b.x;
c.y=a.y-b.y;
return c;
}
inline double sqr(double a)
{
return a*a;
}
inline int Sign(double a)
{
if(fabs(a)<=zero)return 0;
return a<0 ? -1:1;
}
inline bool operator <(Vector a,Vector b)
{
return Sign(b.y-a.y)>0||Sign(b.y-a.y)==0&&Sign(b.x-a.x)>0;
}
inline double Max(double a,double b)
{
return a>b ? a:b;
}
inline double Length(Vector a)
{
return sqrt(sqr(a.x)+sqr(a.y));
}
inline double Cross(Vector a,Vector b)
{
return a.x*b.y-a.y*b.x;
}
Vector dot[maxn],List[maxn];
double opt[maxn][maxn];
int seq[maxn];
int n,len;
double ans;
bool Compare(Vector a,Vector b)
{
int temp=Sign(Cross(a,b));
if (temp!=0)return temp>0;
temp=Sign(Length(b)-Length(a));
return temp>0;
}
void Solve(int vv)
{
int t,i,j,_len;
for(int ii=len=0;ii<n;ii++)
{
if(dot[vv]<dot[ii])List[len++]=dot[ii]-dot[vv];
}
for(i=0;i<len;i++)
for(j=0;j<len;j++)
opt[i][j]=0;
sort(List,List+len,Compare);
double v;
for(t=1;t<len;t++)
{
_len=0;
for(i=t-1;i>=0&&Sign(Cross(List[t],List[i]))==0;i--);
//cout<<i<<endl;
while(i>=0)
{
v=Cross(List[i],List[t])/2.;
seq[_len++]=i;
for(j=i-1;j>=0&&Sign(Cross(List[i]-List[t],List[j]-List[t]))>0;j--);
if(j>=0)v+=opt[i][j];
ans=Max(ans,v);
opt[t][i]=v;
i=j;
}
for(i=_len-2;i>=0;i--)
opt[t][seq[i]]=Max(opt[t][seq[i]],opt[t][seq[i+1]]);
}
}
int i;
double Empty()
{
ans=0;
for(i=0;i<n;i++)
Solve(i);
return ans;
}
int main()
{freopen("t.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&dot[i].x,&dot[i].y);
printf("%.1lf\n",Empty());
}
return 0;
}