传送门
题解:
凸包。
注意 n,m n , m 很大时答案为周长,而周长最小则自动满足凸性,我们只需要枚举起始点即可 O(n2) O ( n 2 ) DP。时间复杂度为 O(n3) O ( n 3 ) 。
n,m n , m 很小的时候我们多记录一个前驱即可。 注意DP要从横纵坐标最小的点开始,不然最后首尾的三个点可能不会满足凸性。
这一部分的时间复杂度为 O(n4) O ( n 4 ) ,预处理的时间复杂度为 O(n2m) O ( n 2 m ) 。
#include
using namespace std;
typedef double DB;
#define R(x) ((x)*(x))
inline long long rd() {
char ch=getchar(); long long i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const DB INF=1e50,eps=0;
inline int sgn(DB x) {return (x>eps)-(x<-eps);}
inline int dcmp(DB x,DB y) {return sgn(x-y)<0;}
const int N=4e2+50;
struct P {
DB x,y,ang; int id;
P(){}
P(DB x,DB y,DB ang=0,int id=0):x(x),y(y),ang(ang),id(id){}
friend inline P operator -(const P &a,const P &b) {return P(a.x-b.x,a.y-b.y);}
friend inline DB operator *(const P &a,const P &b) {return a.x*b.y-a.y*b.x;}
friend inline bool operator <(const P &a,const P &b) {return atan2(a.y,a.x)<atan2(b.y,b.x);}
friend inline DB dis(const P &a,const P &b) {return sqrt(R(a.x-b.x)+R(a.y-b.y));}
}a[N],b[N],c[N];
inline bool cmp_x(const P &a,const P &b) {return a.xinline bool cmp_ang(const P &a,const P &b) {return a.anginline DB cs(int i,int j) {return (a[i]*a[j])*(a[i]*a[j])/(R(a[i].x-a[j].x)+R(a[i].y-a[j].y));}
int n,m,ok[N][N]; DB fib[N],h;
namespace SP1 {
DB f[N][N], ans;
inline void calc(int bg) {
sort(c+bg,c+n+1,cmp_x);
for(int i=bg+1;i<=n;i++) c[i].ang=atan2(c[i].y-c[bg].y,c[i].x-c[bg].x);
sort(c+bg+1,c+n+1,cmp_ang);
for(int i=bg;i<=n;i++)
for(int j=bg;j<=i;j++)
f[i][j]=INF;
f[bg][bg]=0;
for(int i=bg;i<=n;++i) {
for(int j=bg;jif(ok[c[j].id][c[i].id])
for(int k=bg;k!=j+1;++k)
if(sgn((c[i]-c[k])*(c[j]-c[k]))<=0)
f[i][j]=min(f[i][j],f[j][k]+dis(c[i],c[j])*sqrt(h*h+cs(c[i].id,c[j].id))/h);
}
for(int i=bg+1;i<=n;i++) if(ok[c[i].id][c[bg].id])
for(int j=bg;jif(sgn((c[bg]-c[j])*(c[i]-c[j]))<=0) ans=min(ans,f[i][j]+dis(c[i],c[bg])*sqrt(h*h+cs(c[i].id,c[bg].id))/h);
}
inline void solve() {
h=fib[n+m]; ans=INF;
for(int i=1;i<=n;i++) calc(i);
if(dcmp(ans,INF)) printf("%.3lf\n",ans/2.);
else puts("NO SOLUTION");
}
}
namespace SP2 {
DB f[N], ans;
inline void calc(int bg) {
sort(c+bg,c+n+1,cmp_x);
for(int i=bg+1;i<=n;i++) c[i].ang=atan2(c[i].y-c[bg].y,c[i].x-c[bg].x);
sort(c+bg+1,c+n+1,cmp_ang);
for(int i=1;i<=n;i++) f[i]=INF;
f[bg]=0;
for(int i=bg+1;i<=n;++i)
for(int j=bg;j!=i;++j)
if(ok[c[j].id][c[i].id]) f[i]=min(f[i],f[j]+dis(c[i],c[j]));
for(int i=bg+1;i<=n;i++) if(ok[c[i].id][c[bg].id]) ans=min(ans,f[i]+dis(c[i],c[bg]));
}
inline void solve() {
ans=INF;
for(int i=1;i<=n;i++) calc(i);
if(dcmp(ans,INF)) printf("%.3lf\n",ans/2.);
else puts("NO SOLUTION");
}
}
int main() {
while(~scanf("%d%d",&n,&m)) {
fib[1]=1; fib[2]=2;
for(int i=3;i<=n+m && i<=100; ++i) fib[i]=fib[i-1]+fib[i-2];
for(int i=1;i<=n;i++) a[i].x=rd(), a[i].y=rd();
for(int i=1;i<=m;i++) b[i].x=rd(), b[i].y=rd();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(i!=j) {
ok[i][j]=1;
for(int k=1;k<=m&&ok[i][j];k++)
if(sgn((b[k]-a[i])*(a[j]-a[i]))>=0) ok[i][j]=0;
}
for(int i=1;i<=n;i++) c[i]=a[i], c[i].id=i;
if(n+m<=60) SP1::solve();
else SP2::solve();
}
}