题目传送门
分析:
把凸多边形简化成一个圆,一次电车游览会把圆分割成两部分,之后只能在其中一部分里面进行游览
考虑DP,设(F_{i,j,0/1})表示,目前我们只能游览逆时针方向((i,j))中的点,并且下一步是从(i)还是(j)出发
枚举区间中的某个点(k),分类讨论,简单转移
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define maxn 305
#define eps 1e-7
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m;
struct node{
double x,y;
}p[maxn];
double dis[maxn][maxn],f[maxn][maxn][2];
inline double getdis(node x,node y)
{return sqrt(pow(x.x-y.x,2)+pow(x.y-y.y,2));}
int main()
{
int T=getint();
while(T--)
{
memset(dis,0,sizeof dis),memset(f,0,sizeof f);
n=getint();
for(int i=0;i<n;i++)p[i].x=getint(),p[i].y=getint();
m=getint();
for(int i=1;i<=m;i++)
{
int u=getint()-1,v=getint()-1;
dis[u][v]=dis[v][u]=getdis(p[u],p[v]);
f[u][v][0]=f[v][u][0]=f[u][v][1]=f[v][u][1]=dis[u][v];
}
for(int d=n-1;d;d--)for(int i=0;i<n;i++)
{
int j=(i+d)%n;
for(int k=(i+1)%n;k!=j;k=(k+1)%n)
{
if(dis[k][j]>0)
{
f[i][k][1]=max(f[i][k][1],f[i][j][1]+dis[k][j]);
f[k][j][0]=max(f[k][j][0],f[i][j][1]+dis[k][j]);
}
if(dis[i][k]>0)
{
f[i][k][1]=max(f[i][k][1],f[i][j][0]+dis[k][i]);
f[k][j][0]=max(f[k][j][0],f[i][j][0]+dis[k][i]);
}
}
}
double ans=0;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)ans=max(ans,max(f[i][j][0],f[i][j][1]));
printf("%.10lf
",ans);
}
}