UVA1347 旅行 Tour

版权声明:转载请注明出处 https://blog.csdn.net/qq_39541141/article/details/85454458

题面

John Doe想用最小的路程游览完所有目的地。每个目的地都用坐标xi,yi表示。任何两目的地的xi都不相同。两目的地之间的路程是两点之间的直线距离。John是这样走的:他从最左边的点开始,然后只能向右走,走到最右边的点,然后他只能向左走,回到最开始的点。每个点都要走到,并且除了出发点以外每个点只能经过一次。

请写出一个程序求符合要求的最小路程。

思路

似乎“从左到右再回来”不太好想,可以改成“两个人同时从最左端出发,沿着两条不同的路径走,最后走到最右端,除了起点和终点的其他每个点都恰好被一个人经过”。

我们用d(i,j)表示1——max(i,j)全部走过,且两个人的当前位置分别是i和j,还需走的距离。那么就有d(i,j)= d(j,i),因此就从现在开始规定在状态里i>j。这样,不管是那个人,下一步只能走到 i+1,i+2……这些点。但如果走到i+2,情况就会变成“1~i和i+2,但是i+1没走过”,无法表示成状态。

所以,我们禁止这样的决策

也就是说,状态只能转移到d(i+1,j)和d(i+1,i)。不过这样就会导致一个问题:漏解。但这道题并不会,因为如果第一个人直接走到了i+2,那么就不会走到i+1了,所以只能靠第二个人走到i+1。既然如此,就不会丢失解。

另外,边界是d(n-1,j)= dist(n-1,n)+dist(j,n),其中dist(a,b)表示点a和b之间的距离。状态数有n^2个,每个状态的决策有2个,时间复杂度是O(n^2).

                                                                                                                                                                        ——摘自紫书

代码

​
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 56
using namespace std;
int n;
double x[maxn],y[maxn];
double dist[maxn][maxn],d[maxn][maxn];
int main()
{
  while(cin>>n == 1)
  {
    for(int i = 1; i <= n; i++)
      scanf("%lf%lf", &x[i], &y[i]);
    for(int i = 1; i <= n; i++)
      for(int j = 1; j <= n; j++)
        dist[i][j] = sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
    
	for(int i = n-1; i >= 2; i--)
      for(int j = 1; j < i; j++) {
        if(i == n-1) d[i][j] = dist[i][n] + dist[j][n]; 
        else d[i][j] = min(dist[i][i+1] + d[i+1][j],d[i+1][i] + dist[j][i+1]);
      }
    printf("%.2lf\n", dist[1][2]+d[2][1]);
  }
  return 0;
}

​

猜你喜欢

转载自blog.csdn.net/qq_39541141/article/details/85454458
今日推荐