UVA1347 Tour

一. Vjudge链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=38898

二. 题目大意:给你一个二维坐标系上的若干个点,让你从一个点出发,走遍所有的点,并回到当前点,2个点的距离就是其欧几里得距离(初中平面2点距离公式)。求最短的路径。题目的横坐标由小到大依次给出。

三. 思路:(来自紫书)可以把问题转化为:2个人从最左边的点开始走,(除了起点和终点)每个点恰好被2个人其中一个走过。最终2个人一起走到第n个点。

定义dp[i][j]为一个人在第i个点,另一个人在第j个点时离终点n的距离,并且i>j,而且第i个点之前的点全部被走过(意味着每次只能走到i+1个点)。于是我们可以得出,在前n-1个点全部都被走过之后,最后一步肯定是2个人都走向第n个点,也就是开始条件dp[n-1][j] = dist(n-1, n) + dist(j. n),dist表示2个点之间的距离,这是开始条件,因为我们定义的dp[][]是到达终点的距离,然后要转移到前一个状态只要dp[i][j] = min(dp[i+1][j] + dist(i, i+1), dp[i+1][i]+dist(j, i+1)),表示在i位置的人走到i+1或者在j位置的人走到i+1。最后只要dp[2][1]+dist(1,2)就行了。

四. 代码(非递归)

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int MAX_N = 1024,
          INF = 0x3f3f3f3f;

//dp[i][j] 表示第一个人走到第i个点,第二个人走到第j个点,并且i>j,前i个点全部走过,此时离第n个点的距离。
double dp[MAX_N][MAX_N],
       x[MAX_N], y[MAX_N];
int n;

double dist(int i, int j)
{
    return sqrt((x[i]-x[j])*(x[i]-x[j]) +
                (y[i]-y[j])*(y[i]-y[j]));
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i, j;

    while(~scanf("%d", &n)){
        for(i = 1; i <= n; i++)
            scanf("%lf %lf", x+i, y+i);

        for(j = 1; j < n-1; j++)
            dp[n-1][j] = dist(n-1, n) + dist(n, j);

        for(i = n-2; i >= 1; i--)
            for(j = 1; j < i; j++)
                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;
}



你可能感兴趣的:(DP)