UVA

传送门

有n个点,要求从寻找一条从点1到点n,再从n到1的路径,要求这路径经过每个点且没有重复的点,并使得路径总长度最小。输入的是点的坐标<x,y>,保证x值严格递增。点的距离是欧几里得距离。

将问题转化为求解两条互不重叠的从1到n的路径。此时显然从每次走向横坐标更大的值是一个更优的解。我们定义dp[i][j]为当前路径的末尾分别为i,j。显然dp[i][j]==dp[j][i],则我们只用dp[i][j]表示,并严格定义i>j。那么状态转移是dp[i][j] -> dp[i + 1][j](路径i上移动)或 dp[i + 1][i](路径j上移动)。当然dp[i][j]也可以转移到dp[i + 2][i],不过这可以由dp[i][j] ->dp[i + 1][i]->dp[i + 2][i]。所以这个状态转移方程是包含了所有的情况的。

边界条件是已经走了前N-1个点之后,dp[N - 1][j] = distance(N - 1, N) + distance(j, N - 1),最后结果是dp[2][1] + distance(1, 2)

复杂度是O(n2)

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #define INF 0x3f3f3f3f
 7 #define MOD 1000000007
 8 using namespace std;
 9 typedef long long LL;
10 
11 const int maxn = 1e3 + 10;
12 
13 int N;
14 struct node {
15     int x, y;
16 }cor[maxn];
17 
18 double dp[maxn][maxn];
19 
20 double dis(int i, int j) {
21     return sqrt((double)((cor[i].x - cor[j].x) * (cor[i].x - cor[j].x)
22                         + (cor[i].y - cor[j].y) * (cor[i].y - cor[j].y)));
23 }
24 
25 void solve() {
26     memset(dp, 0, sizeof(dp));
27     dp[2][1] = dis(1, 2);
28     for (int i = N - 1; i >= 2; i--) {
29         for (int j = 1; j < i; j++) {
30             if (i == N - 1) {
31                 dp[N - 1][j] = dis(N - 1, N) + dis(j, N);
32             } else {
33                 dp[i][j] = min(dp[i + 1][j] + dis(i, i + 1),
34                                dp[i + 1][i] + dis(j, i + 1));
35             }
36         }
37     }
38     printf("%.2lf
", dp[2][1] + dis(1, 2));
39 }
40 
41 int main(int argc, const char * argv[]) {
42     while (~scanf("%d", &N)) {
43         for (int i = 1; i <= N; i++) {
44             scanf("%d%d", &cor[i].x, &cor[i].y);
45         }
46         solve();
47     }
48     return 0;
49 }
原文地址:https://www.cnblogs.com/xFANx/p/7405025.html