UVA 1347 Tour

来源:互联网 发布:windows 图标文件 编辑:程序博客网 时间:2024/06/06 17:04

题意:给定平面上n个点的坐标(按x递增的顺序给出),要设计一条路线,从最左边的点出发,走到最右边的点后再返回,要求除了最左点和最右点之外每个点恰好经过一次,且路径总长度最短

解题思路:dp.“从左到右再回来”不大方便思考,可以改成:两个人同时从最左点出发,沿着两条不同的路径走,最后都到达最右点,且除了起点和终点外其余每个点恰好被一个人经过。dp[i][j]表示1~max(i,j)全部走过,且两个人的当前位置分别是i和j,还需要走多长的距离。不难发现dp[i][j]=dp[j][i],因此规定在状态中i>j。这样,不管是哪个人,下一步只能走到i+1,i+2,...这些点。也就是说i和j只允许其中一个人走到i+1,而不能走到i+2。换句话说,状态dp[i][j]只能转移到dp[i+1][j]和dp[i+1][i]。边界是dp[n-1][j]=dist[n-1][n]+dist[j][n],根据定义,所有点都走过了,两个人只需要直接走到终点。所求结果就是dist[1][2]+dp[2][1],因为第一步是某个人走到了第二个点,根据定义就是dp[2][1]

代码:

#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>#include <cmath>using namespace std;struct P{    double x,y;}p[100];int n;double dist[100][100],dp[100][100];void dis(){    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++)        {            dist[i][j]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));        }    }}int main(){    while(scanf("%d",&n)==1)    {        for(int i=1;i<=n;i++)        {            scanf("%lf%lf",&p[i].x,&p[i].y);        }        dis();        for(int i=n-1;i>=2;i--)        {            for(int j=1;j<i;j++)            {                if(i==n-1)dp[n-1][j]=dist[n-1][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]);                }            }        }        double ans=dp[2][1]+dist[1][2];        printf("%.2f\n",ans);    }    return 0;}


原创粉丝点击