题意:
有一些房子,构成了一个凸包。
房子之间有铁路。你可以从一个房子出发遍历这些铁路,但是要求路径不能交叉,不能走走过的点。
求最多走多少距离。
思路:
环上的区间DP。
将房子看做圆,走了 i − > j i->j i−>j后,就相当于把圆分为了两半,之后只能走其中一半。
定义 f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]为还可以逆时针走 ( i , j ) (i,j) (i,j)部分的点,且下一次出发的点为 i ( j ) i(j) i(j)的最大所走距离。
因为我们规定了是逆时针方向的走,相当于是将区间扩大了一倍,这就不用担心环形结构的影响了。
之后就按照区间DP进行转移。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 305;
struct Node {
double x,y;
}a[maxn];
double f[maxn][maxn][2],dis[maxn][maxn];
double get(Node a,Node b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main() {
int T;scanf("%d",&T);
while(T--) {
int n;scanf("%d",&n);
for(int i = 0;i < n;i++) {
scanf("%lf%lf",&a[i].x,&a[i].y);
}
memset(f,0,sizeof(f));
memset(dis,0,sizeof(dis));
int m;scanf("%d",&m);
for(int i = 0;i < m;i++) {
int x,y;scanf("%d%d",&x,&y);
x--;y--;
f[y][x][0] = f[y][x][1] = f[x][y][0] = f[x][y][1] = dis[x][y] = dis[y][x] = get(a[x],a[y]);
}
for(int len = n - 1;len >= 1;len--) {
for(int i = 0;i < n;i++) {
int j = (i + len) % 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[i][k]);
f[k][j][0] = max(f[k][j][0],f[i][j][0] + dis[i][k]);
}
}
}
}
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("%.10f\n",ans);
}
return 0;
}