UVa 01347
John Doe准备去n
个地方旅游,然后再回到起点。他租了一架飞机。为了省钱,他要保证每个地方只去一次,另外他打算到最远地方后才往回飞,所以需要计算出一个最短的闭环路径。
假如现在在第i
个景点,那么下一次可以飞向任何一个更远的景点。虽然这一步的选择在当下没有什么影响,但是会影响到回来时的选择,所以这一步的决策应该兼顾到回来的路线。假如直接飞往第i + 2
个景点,那么第i + 1
个景点只能是回来时候再去了,可是应该从哪一个景点回到第i + 1
个景点却不得而知,因为那都是未来才会发生的事情。
虽然不知道从哪个景点飞回来,但是知道到达第i + 1
个景点后的下一站是哪里,也就是说在第i
个景点时,出发的前一半路程是确定的,以及回来的后一半路程也是确定的,所以可以将回来的后一半路程也转化为出发的前一半路程,这样问题就转化为了从出发点开始,找到两条完全不同的到达最远景点的路线,使飞行距离最小。
转化之后再来找递推关系。假设在路线1
(出发路线)上处于景点i
,在路线2
(回来路线)上处于景点j
,同时假设i > j
,最短距离为dist(i, j)
。如果在路线1
上游览景点i + 1
,那么路线2
还依然停留在景点j
就好了;假如在路线2
上游览景点i + 1
,那么在路线1
上依然停留在景点i
,不满足i > j
的关系,但是因为路线1
和路线2
是可交换的,所以dist(i, i + 1)
和dist(i + 1, i)
是等价的,因此可以从dist(i, j)
递推得到dist(i + 1, j)
和dist(i + 1, i)
。
如果在路线1
上游览景点i + 2
,那么必须要在路线2
上游览景点i + 1
,所以亦可以从dist(i, j)
递推得到dist(i + 2, i + 1)
,而这个状态可以从dist(i + 1, j)
得到,最终也是可以从dist(i, j)
得到,所以每次只要对最近的景点进行决策即可。
最后还需要补充计算一下路线1
到达终点时路线2
距终点的距离,这样才是完整的闭环距离。
#include <iostream>
#include <vector>
#include <array>
#include <iomanip>
#include <cmath>
#include <cfloat>
#define EPS 1e-6
using namespace std;
struct Point
{
int x, y;
Point(const int x, const int y) : x(x), y(y) {}
};
bool operator<(const Point &p1, const Point &p2)
{
return p1.x < p2.x;
}
double calDistance(const Point &p1, const Point &p2)
{
double x = (double)(p1.x - p2.x);
double y = (double)(p1.y - p2.y);
return sqrt(x * x + y * y);
}
void findShortestTour(const vector<Point> &vecPoint)
{
const size_t points = vecPoint.size();
vector<vector<double>> distance(points, vector<double>(points, DBL_MAX));
double go, back;
distance[1][0] = calDistance(vecPoint[0], vecPoint[1]);
for (size_t i = 1; i < points - 1; i++)
{
go = calDistance(vecPoint[i], vecPoint[i + 1]);
for (size_t j = 0; j < i; j++)
{
back = calDistance(vecPoint[j], vecPoint[i + 1]);
if (distance[i + 1][j] > distance[i][j] + go + EPS) {
distance[i + 1][j] = distance[i][j] + go;
}
if (distance[i + 1][i] > distance[i][j] + back + EPS) {
distance[i + 1][i] = distance[i][j] + back;
}
}
}
for (size_t j = 0; j < points - 1; j++)
{
back = calDistance(vecPoint[j], vecPoint.back());
if (distance[points - 1][points - 1] > distance[points - 1][j] + back + EPS) {
distance[points - 1][points - 1] = distance[points - 1][j] + back;
}
}
cout << fixed << setprecision(2) <<distance[points - 1][points - 1] << endl;
}
int main()
{
int number;
while (cin >> number) {
vector<Point> vecPoint;
int x, y;
for (int i = 0; i < number; i++)
{
cin >> x >> y;
vecPoint.push_back(Point(x, y));
}
findShortestTour(vecPoint);
}
return 0;
}
/*
3
1 1
2 3
3 1
4
1 1
2 3
3 1
4 2
*/