题意:
题意就是双调旅行商。
John uses the following strategy: he starts from the leftmost point, then he goes strictly left to right to the rightmost point, and then he goes strictly right back to the starting point. It is known that the points have distinct x-coordinates.
这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点,并且每个x是独一无二的。
然后求最小距离的花费。
解析:
先将坐标按照x轴从小到大排序。
dp[i][j]代表从 i 到 j 的最小花费。
定义从Pi到Pj的路径为:从Pi开始,从右到左一直到P1,然后从左到右一直到Pj。
在这个路径上,会经过P1到Pmax(i,j)之间的所有点且只经过一次。
首先,若 1 <= i < j - 1:
如上图,此时 dp[ i ] [ j ] = dp[ i ] [ j - 1] + dist( j - 1, j )。
这个很好理解,直接到点 1 然后点 1 到 j-1 然后到j的距离。
其次,当 i == j - 1, 1 <= k < j - 1
此时,若还像情况一那样连接的话,点 j-1 和点 j 将会直接连成闭合线,直接忽视n,这种情况不存在。
所以,此时从前面的点1 ~ j - 2 这些点中找到一个满足条件最小的点k, 此时k + 1 ~ j - 2的点全部被放到了下面,然后k直接和点j相连。
即:dp[ i ] [ j ] = dp[ j - 1] [ j ] = min( dp[j - 1] [ k ] + dist(k, j) );
最后再加上闭环 dp[n - 1][n] + dist(node[n - 1], node[n]); 就行了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 520;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
struct Node
{
double x, y;
} node[maxn];
int n;
double dp[maxn][maxn];
bool cmp(Node a, Node b)
{
return a.x < b.x;
}
double dist(Node a, Node b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double DP()
{
dp[1][2] = dist(node[1], node[2]);
for (int j = 3; j <= n; j++)
{
//i < j - 1
for (int i = 1; i < j - 1; i++)
{
dp[i][j] = dp[i][j - 1] + dist(node[j - 1], node[j]);
}
// i = j - 1
dp[j - 1][j] = inf;
for (int k = 1; k < j - 1; k++)
{
double t = dp[k][j - 1] + dist(node[k], node[j]);
if (t < dp[j - 1][j])
{
dp[j - 1][j] = t;
}
}
}
return dp[n - 1][n] + dist(node[n - 1], node[n]);
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf", &node[i].x, &node[i].y);
}
sort(node + 1, node + n + 1, cmp);
printf("%.2lf\n", DP());
}
return 0;
}