题目
思路
1.抽象(神乎其技):由于从左到右不方便思考,可以将问题转换为,两个人同时从最左点出发,沿着两条路径走,最后都走到最右点,并且除了起点和终点外每个点恰好被一个人走过。
2.状态定义:(i,j),表示1~i已经全部走过,且两个人分别位于i,j(i>j)。
3.指标函数:d(i,j),还需要走的距离。
4.状态转移方程:
本题的难点,在于推理出合适的状态定义:
代码
由于double不能批量赋值为-1,所以本代码采用了vis数组,空间换易读性。
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 1 << 30;
const int maxn = 1000 + 100;
int n;
double d[maxn][maxn], dist[maxn][maxn], vis[maxn][maxn];
struct Point {
int x, y;
}A[maxn];
double dp(int i, int j) {
double &ans = d[i][j];
if (vis[i][j]) return ans;
double d1 = dp(i + 1, j) + dist[i][i + 1];
double d2 = dp(i + 1, i) + dist[j][i + 1];
ans = min(d1, d2);
vis[i][j] = 1;
return ans;
}
int main() {
while (scanf("%d", &n) == 1) {
_rep(i, 1, n) scanf("%d%d", &A[i].x, &A[i].y);
_rep(i, 1, n)
_rep(j, 1, n)
dist[i][j] = dist[j][i] = sqrt(pow(A[i].x - A[j].x, 2) + pow(A[i].y - A[j].y, 2));
//memset(d, -1.0, sizeof(d)); // double不可以批量赋值-1
memset(vis, 0, sizeof(vis));
d[n][n - 1] = 0.0; vis[n][n - 1] = 1;
_rep(i, 1, n - 2) {
d[n][i] = 1.0 * INF;
vis[n][i] = 1;
}
double ans = dp(1, 1);
printf("%.2lf\n", ans+dist[n-1][n]);
}
return 0;
}