简要题意:
有一些要被围起来的点,有一些木桩,请你以这些木桩为顶点构造一个凸多边形,使得要求的点全部在其内部,同时在原点处有一个最高点,请你最小化以你选择的凸多边形为底面的椎体的侧面积。
凸包DP SB题一道。
考场上没看到凸多边形的限制去想凹的情况了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const
using std::cerr;
using std::cout;
template<typename T>
void ckmin(T &a,cs T &b){a>b?a=b:0;}
struct Pnt{
int x,y;Pnt(){}Pnt(int _x,int _y):x(_x),y(_y){}
friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y+b.y);}
friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
friend ll operator*(cs Pnt &a,cs Pnt &b){return (ll)a.x*b.y-(ll)b.x*a.y;}
inline db len()cs{return sqrt((ll)x*x+(ll)y*y);}
};
inline ll crs(cs Pnt &a,cs Pnt &b,cs Pnt &c){
return (ll)(b.x-a.x)*(c.y-a.y)-(ll)(c.x-a.x)*(b.y-a.y);
}
cs int N=4e2+7;
int n,m;
ll fib[80],h;
bool ok[N][N];
Pnt p[N],q[N];
int id[N][800],ct[N];
inline ll crs(int a,int b,int c){
return crs(p[a],p[b],p[c]);
}
inline db dis(int a,int b){return (p[a]-p[b]).len();}
inline db calc(cs Pnt &a,cs Pnt &b){
db len=(a-b).len();
if(h==0)return len*.5;
db d=fabs(a*b)/len/h;
return len*sqrt(d*d+1)*.5;
}
inline db calc(int a,int b){
return calc(p[a],p[b]);
}
int ql[N],tl;
int qr[N],tr;
void get_lr(int o,int t){
int ps;for(ps=2;ps<=ct[t];++ps)
if(crs(t,o,id[t][ps])==0)break;
tl=tr=0;ql[++tl]=id[t][ps];
for(int re i=ps+1;i<ps+ct[t];++i)if(id[t][i]>o){
if(crs(t,o,id[t][i])>0){
if(ok[id[t][i]][t])ql[++tl]=id[t][i];
}else {
if(ok[t][id[t][i]])qr[++tr]=id[t][i];
}
}
}
db f[N][N];
db calc(int o){
for(int re i=o;i<=n;++i)
for(int re j=o;j<=n;++j)f[i][j]=1e16;
bool flag=false;
for(int re i=o+1;i<=n;++i)
if(ok[o][i])f[o][i]=calc(o,i),flag=true;
if(!flag)return 1e16;
std::vector<int> ps;
for(int i=o+1;i<=n;++i)ps.push_back(i);
std::sort(ps.begin(),ps.end(),[o](int a,int b){
return crs(o,a,b)?crs(o,a,b)>0:dis(o,a)<dis(o,b);});
for(int t:ps){
get_lr(o,t);db tmp=1e16;
for(int re il=1,ir=1;ir<=tr;)
if(il>tl||crs(t,ql[il],qr[ir])>0)
f[t][qr[ir]]=tmp+calc(t,qr[ir]),++ir;
else
ckmin(tmp,f[ql[il]][t]),++il;
}db res=1e16;
for(int re i=o+1;i<=n;++i)if(ok[i][o])
for(int re j=o+1;j<=n;++j)
ckmin(res,f[j][i]+calc(i,o));
return res;
}
void work(){
for(int re i=1;i<=n;++i)
scanf("%d%d",&p[i].x,&p[i].y);
for(int re i=1;i<=m;++i)
scanf("%d%d",&q[i].x,&q[i].y);
std::sort(p+1,p+n+1,[](cs Pnt &a,cs Pnt &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);});
h=n+m>=75?0:fib[n+m];
for(int re i=1;i<=n;++i)
for(int re j=1;j<=n;++j){
bool &flag=ok[i][j]=true;
for(int re k=1;k<=m;++k)
flag&=crs(p[i],p[j],q[k])>0;
}
for(int re i=1;i<=n;++i){
int *id=::id[i];
for(int re j=1;j<=n;++j)id[j]=j;
id[i]=1;
std::sort(id+2,id+i+1,[i](int a,int b){
return crs(i,a,b)?crs(i,a,b)>0:(dis(i,a)<dis(i,b));});
std::sort(id+i+1,id+n+1,[i](int a,int b){
return crs(i,a,b)?crs(i,a,b)>0:(dis(i,a)<dis(i,b));});
int &t=ct[i]=2;
for(int re j=3;j<=n;++j)
if(crs(i,id[t],id[j])||(id[t]<i&&id[j]>i))
id[++t]=id[j];
for(int re j=t+1;j<t+t;++j)id[j]=id[j-t+1];
}
db ans=1e16;
for(int re i=1;i<=n;++i)
ans=std::min(ans,calc(i));
if(ans<1e16)printf("%.3lf\n",ans);
else puts("NO SOLUTION");
}
void Main(){
fib[0]=fib[1]=1;
for(int re i=2;i<=75;++i)
fib[i]=fib[i-1]+fib[i-2];
while(~scanf("%d%d",&n,&m))work();
}
inline void file(){
#ifdef zxyoi
freopen("tent.in","r",stdin);
cerr<<std::fixed<<std::setprecision(3);
cout<<std::fixed<<std::setprecision(3);
#endif
}
signed main(){file();Main();return 0;}