给定平面上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; }
时间: 2024-10-25 21:10:16