首先做一个转化,这种转化很常见。
题目里面讲要来回走一遍,所以就转化成两个从起点到终点,路径不重合
那么很容易想到用f[i][j]表示第一个走到i,第二个人走到j还需要走的距离
但是这里无法保证路径不重合,所以这里怎么设计状态很关键。
我们设f[i][j]是1到max(i, j)全部走过,同时第一个在i,第二人在j,
还需要走的距离,可以看出f[i][j] = f[j][i],所以我们可以规定i > j
那么这么规定有什么好处呢?我们可以让两个人走的路径是1, 2, 3, 4……
换句话说,当前是f[i][j],根据定义,1到i全部走过,接下来要走到第i+1个位置
假设是第一个人走,也就是在i的这个人走,那么可以从f[i][j]转移到f[i+1][j]
假设是第二个人走,也就是在j的这个人走,那么可以从f[i][j]转移到f[i+1][i](j到i+1,而规定前面的要大)
dist[i][j]表示i到j的欧几里得距离
边界是f[n-1][j] = dist[i][n] + dist[j][n]最后的时候肯定是两个人走到终点,我们要从终点逆推
最终答案是d[2][1] + dist[2][1]。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;const int MAXN = 55;
double x[MAXN], y[MAXN], dist[MAXN][MAXN], d[MAXN][MAXN];int main()
{int n;while(~scanf("%d", &n)){REP(i, 1, n + 1) scanf("%lf%lf", &x[i], &y[i]);REP(i, 1, n + 1)REP(j, 1, n + 1)dist[i][j] = sqrt(pow(x[i]-x[j], 2) + pow(y[i]-y[j], 2));for(int i = 2; i <= n; i++)REP(j, 1, i){if(i == 2) d[i][j] = dist[1][2];else d[i][j] = min(d[i+1][j] + dist[i][i+1], d[i+1][i] + dist[i+1][j]);}printf("%.2lf\n", d[2][1] + dist[2][1]);}return 0;
}