UVA - 1347 Tour(最短路dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/80551364

好久没有正儿八经地刷过UVA上的题了,来水一发。

这道题乍一看挺像旅行商的NPC问题,仔细想想是个dp。

一开始我看了看紫书上的做法,还纳闷为什么一定要按照按照x从左到右走才是最短路,推了半天没有推出来。重新读了读英文原题才恍然大悟,goes strictly left to right...

其实就是假设两个人同时从最左边的点出发,一直走到右边,所求结果就是两个人所走的距离之和的最小值。

我们用dp(i,j)表示两个人一个走到i,另一个走到j,并且i与j之间所有的点均被走完(因为题目要求严格从左到右或者从右到左,所以不会出现折返的情况)的情况下,还需要走的最短的距离。注意i永远是i和j之间较大的那一个,便于处理。

这样一来,每一步无非就两种情况:第一个人走到下一点,或者第二个人走到下一点,由此可得出状态转移方程:dp(i,j)=min(dp(i+1,j)+dist(i,i+1),dp(i+1,i)+dist(j,i+1)),总状态数的数量级为n^2。dist(i,j)代表两点间的欧几里得距离。

递归边界为dp(n-1,j)=dist(n-1,n)+dist(j,n),此时一个点走到了n-1,另一个点走到了j,只剩下最右边的点没有走了,所以距离就是点n-1到点n的距离加上点j到点n的距离。最终所求的结果为dp(1,1)。

AC代码:

#include<bits/stdc++.h>
#define FRER() freopen("i.txt","r",stdin)

using namespace std;
const int N=1000+100;
double x[N],y[N],d[N][N];
int n,vis[N][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]));
}
double dp(int i,int j)
{
    if(i==n-1)
        return dist(i,n)+dist(j,n);
    if(vis[i][j])
        return d[i][j];
    d[i][j]=min(dp(i+1,j)+dist(i,i+1),dp(i+1,i)+dist(j,i+1));
    vis[i][j]=1;
    return d[i][j];
}

int main()
{
    while(scanf("%d",&n)==1)
    {
        memset(vis,0,sizeof vis);
        for(int i=1; i<=n; ++i)
            scanf("%lf%lf",&x[i],&y[i]);
        printf("%.2f\n",dp(1,1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/80551364
今日推荐