这两题都是双调TSP问题,我们定义dp[i][j]表示两个人从最左端开始一起向右走,当然中间不会有相交(相交的话一定不是最优解-> 三角形 a + b > c)
所走的最短路径,最后答案就是dp[n][n]
规定i > j,第一个人走在前面(显然两条路径是等价的,所以无所谓谁前谁后,这里规定一下比较好处理)
当j < i - 1
第二个人在j时,第一个人一定是从i - 1转移到i的,否则i-1就空下来了
dp[i][j] = dp[i - 1][j] + dist(i - 1, i);
当j == i - 1
当第二个人紧紧跟在第一个人后面,那么第一个人从位置k转移到i(1 <=k <= i - 2)
dp[i][j] = min(dp[k][j] + dist(k, i);
但是dp这个状态都只计算了i>j的状态,而这里k < j,所以把它变成dp[j][k];
dp[i][j] = min(dp[j][k] + dist(k, i);
那么最后就只要计算下dp[n][n]就好了
循环计算到最后得出的是dp[n][n - 1]的最优解
#include <map> #include <set> #include <list> #include <queue> #include <stack> #include <vector> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:102400000, 102400000") using namespace std; const int N = 210; double dp[N][N]; struct point { int x, y; }p[N]; int cmp(point a, point b) { return a. x < b.x; } double dis(point a, point b) { return sqrt ((double)((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y))); } int main() { int n; while(~scanf("%d", &n)) { for (int i = 1; i <= n; ++i) { scanf("%d%d", &p[i].x, &p[i].y); } sort (p + 1, p + n + 1, cmp); dp[1][2] = dp[2][1] = dis(p[1], p[2]); for (int i = 3; i <= n; ++i) { for (int j = 1; j <= i - 2; ++j) { dp[i][j] = dp[i - 1][j] + dis(p[i], p[i - 1]); } double tmp = 0x3f3f3f3f; //j == i - 1 for (int j = 1; j <= i - 2; ++j) { tmp = min(tmp, dp[i - 1][j] + dis(p[i], p[j])); } dp[i][i - 1] = tmp; } dp[n][n] = dp[n][n - 1] + dis(p[n], p[n - 1]); printf("%.2f\n", dp[n][n]); } return 0; }