有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 }