题目大意
给出一个凸包,让你求一个不包含一些点的新凸包,用原来凸包上的点。
解题思路
新的凸包可以割成若干个三角形,三角形内部一定不包含那些点,所以外部的点一定等于总点数。我们可以求出一条线一边所含点的个数,可是这有交集。考虑到新凸包上的点是原凸包的子集,交集一定在原凸包外。我们就可以n^2预处理出那些点在凸包内,n^3处理处一条线一边的点数,再n^3DP。判断点可以使用叉积,求出相对方向即可判断是否在凸包内和在一条线的哪边,枚举起点,f[i]表示到i的最优答案,枚举j下一个选谁,转移即可。
code
using namespace std;
int const maxn=100,maxm=400;
LL n,m,x[maxn+10],y[maxn+10],p[maxm+10],q[maxm+10],cnt[maxn+10][maxn+10],cntt[maxn+10][maxn+10];
bool in[maxm+10];
LL f[maxn+10];
LL count(LL x,LL y,LL xx,LL yy){
return x*yy-y*xx;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%lld",&n);
fo(i,1,n)
scanf("%lld%lld",&x[i],&y[i]);
scanf("%lld",&m);
fo(i,1,m)
scanf("%lld%lld",&p[i],&q[i]);
LL pon=0;
fo(i,1,m){
in[i]=1;
fo(j,1,n)
if(count(x[j%n+1]-x[j],y[j%n+1]-y[j],p[i]-x[j],q[i]-y[j])<0){
in[i]=0;
break;
}
pon+=in[i];
}
fo(i,1,n)
fo(j,1,n)
if(i!=j)
fo(k,1,m)
if(in[k])
cnt[i][j]+=(count(x[j]-x[i],y[j]-y[i],p[k]-x[i],q[k]-y[i])<=0);
LL ans=0;
fo(i,1,n-2){
memset(f,0,sizeof(f));
fo(j,i+1,n-1)
fo(k,j+1,n)
if(cnt[i][j]+cnt[j][k]+cnt[k][i]==pon)
f[k]=max(f[k],f[j]+abs(count(x[k]-x[i],y[k]-y[i],x[j]-x[i],y[j]-y[i])));
fo(j,i+2,n)ans=max(ans,f[j]);
}
if(ans==0)printf("die");
else printf("%.2lf",ans/2.0);
return 0;
}