这两题都是双调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;
}