题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2224
题意:平面上有n个点,问去的路只能从左到右,回的路只能从右到左的,且来回必须经过所有点的最小路径;
dp[i][j] 表示以j为起点,1为拐点 ,i为终点的最短路;
j < i-1 时,那么i-1这个点在来的路径上 必然等于dp[i-1][j] + dis[i-1][i] ;
j = i -1 ,那么i-1这个点在回的路径上,那么dp[i][j] = min(dp[k][j] + dis[k][j]) 1<=k < j; 因为dp[i][j] = dp[j][i], 所以dp[i][j] = min(dp[j][k] + dis[k][j]) 1<=k < j
#include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <iostream> #include <time.h> #include <vector> #include <queue> typedef long long LL; using namespace std; const int N = 205; const double eps = 1e-6; const int INF = 0x3f3f3f3f; const int mod = 1000000007; const double PI = 4*atan(1.0); struct point { double x, y; }p[N]; double Dist(point p1, point p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } int n; double dp[N][N];///表示以j为起点,1为拐点,i为终点,经历所有i到j之间的点; /* double DP() { dp[1][1] = 0; dp[2][1] = Dist(p[1], p[2]); for(int i=3; i<=n; i++) { for(int j=1; j<i-1; j++) dp[i][j] = dp[i-1][j] + Dist(p[i-1],p[i]); double Min = INF; for(int k=1; k<i-1; k++) Min = min(Min, dp[i-1][k] + Dist(p[k], p[i])); dp[i][i-1] = Min; } dp[n][n] = dp[n][n-1] + Dist(p[n-1], p[n]); return dp[n][n]; }*/ double DFS(int s, int e) { if(dp[s][e] != 0) return dp[s][e]; if(s < e-1) dp[s][e] = DFS(s, e-1) + Dist(p[e-1], p[e]); else { double Min = INF; for(int i=1; i<e-1; i++) Min = min(Min, DFS(i, s) + Dist(p[i], p[e])); dp[s][e] = Min; } return dp[s][e]; } int main() { while(scanf("%d", &n) != EOF) { memset(dp, 0, sizeof(dp)); for(int i=1; i<=n; i++) scanf("%lf %lf", &p[i].x, &p[i].y); ///double ans = DP(); dp[1][1] = 0; dp[2][1] = dp[1][2] = Dist(p[1], p[2]); DFS(n-1, n); dp[n][n] = dp[n-1][n] + Dist(p[n-1], p[n]); printf("%.2f ", dp[n][n]); } return 0; }