uva - 1347 Tour ( 動態規劃 + 遞歸 )

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



一道動態規劃的題目,題意大概是要把給出的幾個點全部走一遍,走一個圈回到起點,要求走的距離最短。

這題的思路可以轉化成兩人同時從起點出發,朝兩個方向向終點前進,且不會走重複的點。如何判斷這個點是否已經走過的了是一個難點。我的方法是遞歸函數,每次輸入的是i和j,表示最前面的兩個點(i表示前面的點,j表示後面的點),每次如果的是i向前走一個點 函數(i+1,i),因爲j點走到了i的前面,i反而成了後面的點。同理j向前走之後函數的表達式變爲 函數(i+1,j)。並且建立一個二維數組dp[ ][ ],來儲存已經走了的距離。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
struct node      
{
    int x,y;
}v[1010];                   //用來儲存各個點。

double dp[1010][1010];
int n;
double dd(node a,node b)    //用於計算距離的函數
{
    return sqrt((a.y-b.y)*(a.y-b.y)+(a.x-b.x)*(a.x-b.x));
}

double dg(int i,int j)      //實現上面解釋中的函數()功能
{
    if(i == n-1)
        return dd(v[n],v[n-1])+dd(v[j],v[n]);
    if(dp[i][j]>0) return dp[i][j];
    return dp[i][j] = min(dg(i+1,j)+dd(v[i],v[i+1]),dg(i+1,i)+dd(v[j],v[i+1]));

}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    while(cin>>n&&n)
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            cin>>v[i].x>>v[i].y;
        }
        for(int i=1;i<n-1;i++)
            dp[n-1][i]=dd(v[n],v[n-1])+dd(v[i],v[n]);   //初始化每個dp[][]的值,來減小後續的運算量
        double ans=dg(1,1);

        printf("%.2lf\n",ans);

    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章