UVA1347 Tour

题目大意:
给你n个坐标
按x递增顺序给出坐标
让一个人按严格x递增顺序走到最后一个点
之后再从最后一个点严格向左走回来
要求走的时候除了起点终点经过两次以外其他点全部都经过一次
问最短路径

思路:dp
这里紫书的第一个图是有问题的
题目要求人向右走的时候x要严格增加,向左走的时候严格变小
不能经过一个超过1个点坐标的时候又反过来走
不然如果可以这题是无解的
思路就是两个人从起点出发走两条没有相同点的路径最终走到终点
设dp[i][j]表示第1个人走到第i点,第二个人走到第j点还需要多少距离到终点
因为dp[j][i]跟dp[i][j]一个意思,第一个人走或者第二个走是没区别的
为了方便设i>j(肯定不能等于,不能走相同的点)
那么为了走过所有的点我们在第1个人走到第i点,第二个人走到第j点的时候后有两种情况
要么第一个人走到i+1的点
要么第二个人走到i+1的点
因为只能递增着走,而且又要经过所有点,所以就这两种情况
又因为i>j,当第二个人走到i+1的点的时候dp[i][j]就变成了dp[i+1][i]
然后因为一开始的时候第一个点肯定要走到第二个点的(无论是谁,总有一个人要走,那就让第一个人走因为i>j)
我们设的状态又是i>j的
所以算答案的时候不能算dp[1][1],要是dp[2][1]+第一个点到第二个点的距离
然后计算每个转移的最小值就好啦

AC代码:

#include <bits/stdc++.h>
#define pf(x) (x)*(x)
using namespace std;
struct node{
    int x,y;
}a[1010];
int n;
double calc_dist(node x,node y){return sqrt(pf(x.x-y.x)+pf(x.y-y.y));}
double dp[1010][1010];
double dist[1010][1010];
int v[1010][1010];
double solve(int i,int j){
    if(dp[i][j])return dp[i][j];//记忆化搜素
    if(i==n-1)return dist[n][j]+dist[i][n];
    else return dp[i][j]=min(solve(i+1,j)+dist[i][i+1],solve(i+1,i)+dist[i+1][j]);
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            cin>>a[i].x>>a[i].y;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                dist[i][j]=dist[j][i]=calc_dist(a[i],a[j]);
            }
        }
         printf("%.2lf\n",dist[1][2]+solve(2,1));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值