Tour
John Doe, a skilled pilot, enjoys traveling. While on vacation, he rents a small plane and starts visiting beautiful places. To save money, John must determine the shortest closed tour that connects his destinations. Each destination is represented by a point in the plane pi = < xi, yi > . 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.Write a program that, given a set of n points in the plane, computes the shortest closed tour that connects the points according to John's strategy.
Input
The program input is from a text file. Each data set in the file stands for a particular set of points. For each set of points the data set contains the number of points, and the point coordinates in ascending order of the x coordinate. White spaces can occur freely in input. The input data are correct.
Output
For each set of data, your program should print the result to the standard output from the beginning of a line. The tour length, a floating-point number with two fractional digits, represents the result.
Note: An input/output sample is in the table below. Here there are two data sets. The first one contains 3 points specified by their x and y coordinates. The second point, for example, has the x coordinate 2, and the y coordinate 3. The result for each data set is the tour length, (6.47 for the first data set in the given example).
Sample Input
3
1 1
2 3
3 1
4
1 1
2 3
3 1
4 2
Sample Output
6.47
7.89
这道题是一道经典问题,为双调欧几里德旅行商问题。
双调路径:从最左点开始,严格的从左到右直至最右点,然后严格的从右到左,直至出发点,其中,两路线除了起始点意外,不允许有任何重复的点。这就是双调路线。
此题通过时间复杂度为O(N^2)的动态规划解决方法解决。
为简便起见,我们设两路径均为从最左点开始,直至最右点。我们定义dp[i][j]为两路线现在一个到达了i点、另一个到达了j点,其中i>j。
那么对于状态dp[i][j],我们有两种行走方式,一种是由i行走之i+1,另一种是由j行走至i+1,此处应留意i>j,且行至i+1所获得的答案会比行至i+k(k>1)所获得的答案更优。
从而获得状态转移方程:
1. dp[i][j]=dp[i+1][j]+dist[i][i+1];
2. dp[i][j]=dp[i+1][i]+dist[j][j+1];
最后边界为两路线汇聚在点n,所以dp[n-1][j]=dist[n-1][n]+dist[j][n];。
答案为dp[1][1]=dp[2][1]+dist[1][2];
至此,题目得以解决。
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN (50+5)
struct NODE{
double x,y;
bool operator < (const NODE& rhs) const {return x<rhs.x;}
};
int n;
NODE a[MAXN];
double dist[MAXN][MAXN],dp[MAXN][MAXN];
double dkj(int i,int j){
double x1=a[i].x,x2=a[j].x;
double y1=a[i].y,y2=a[j].y;
return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++)scanf("%lf%lf",&a[i].x,&a[i].y);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j)dist[i][j]=dkj(i,j);
}
}
for(int i=n-1;i>=2;i--){
for(int j=1;j<i;j++){
if(i==n-1){dp[i][j]=dist[i][n]+dist[j][n];}
else{
dp[i][j]=min(dp[i+1][j]+dist[i][i+1],dp[i+1][i]+dist[j][i+1]);
}
}
}
printf("%.2lf\n",dp[2][1]+dist[1][2]);
}
return 0;
}