第四十八题 UVA1347 旅行 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

紫书上的例题 质量超级高
分析:
1.首先需要将原问题转化为,两个人A、B同时从最左边的点出发,一起严格向最右点走,且经过所有点一次(除了最左点和最右点)。这与原题的要求具有等价性。
2.先自然想到用dp(i,j)表示A走到i,B走到j时的状态还需要走多远到终点(注意表示的是还有多少到终点,所以其结果与前面怎么走的无关),那么可以证明dp(i,j)==dp(j,i);这里有的人可能会疑惑为什么会相等,刚刚说过dp(i,j)表示 已经 达到这个状态后还需要走多远到达终点,与怎么到达这个状态的并没有关系,所以dp(i,j)和dp(j,i)只是两个人角色对换了而已。
3.想到这一步之后,会出现一个问题,就是dp(i,j)无法知道i、j之间的某些点是否已经走过了,所以我们需要进一步思考,刚刚我们提到,dp(i,j)==dp(j,i),那么我们就可以始终让i>=j(等于只有终点和起点达到)。如果j>i了,只需要交换A、B的角色即可,即将i换为j,j换为i。
4.有了这个条件之后,我们就可以规定dp(i,j)规定为:A在i,B在j(i>=j)且i之前的所有点都走过了,这样也不会漏解,为什么呢?我们的自然的方法中,之所以i~j之间有点不知道走过了没,就是因为我们允许A连续走了多步,比如A从P1->P5->P6,而B可能从P1->P2。所以P3,P4我们不知道有没有被A或者B走到,因为我们只知道A走到了P6而B走到了P2。但是你明显发现了,在刚刚那个例子中,P3、P4之后必须要被B走到。所以我们改进的dp(i,j)中可以让A和B一格一格走,要么A走,要么B走(其实只是让顺序变化了一下而已)。
5.有了刚刚的论证,我们的状态转移就变成了下面这样:
dp[i][j] = min(DP(i + 1, j) + dist(i, i + 1), DP(i + 1, i)+dist(j,i+1));
即要么A走,要么B走,如果A走的话,那么走到状态dp(i+1,j);如果B走,那么走到状态dp(i,i+1)到要求前面大于后面,所以dp(i,i+1)==dp(i+1,i)即可。注意dist(i,j)表示i-j的距离。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define Maxn 1005

using namespace std; 
int x[Maxn],y[Maxn];
int n;
double f[Maxn][Maxn];
inline double Dist(int p,int q) { return sqrt((x[p] - x[q]) * (x[p] - x[q]) + (y[p] - y[q]) * (y[p] - y[q])); }

double DFS(int i,int j ) {
	if(f[i][j] > 0) return f[i][j];
	return f[i][j] = min(DFS(i + 1,j) + Dist(i,i + 1) , DFS(i + 1,i) + Dist(j,i + 1));
}

int main(int argc,char* argv[]) {
	while(scanf("%d",&n) == 1) {
		for(int i=1; i<=n; i++) scanf("%d %d",&x[i],&y[i]);
		memset(f,0,sizeof(f));
		for(int j=1; j<n-1; j++)
			f[n-1][j] = Dist(n - 1,n) + Dist(j,n);
		double ans = DFS(1,1);
		printf("%.2lf\n",ans);
	}
	
	return 0;
}

在网上还看见一个叫啥 双调欧几里得旅行商问题的解法,本题还是那种方法的例题,,那种算法我看了看效率好像更高,但是原理好像不太明白
粘一下大佬的博客,感想去的可以去看一下 https://blog.csdn.net/xiajun07061225/article/details/8092247

发布了732 篇原创文章 · 获赞 31 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/qq_35776409/article/details/104024566