Uva 1347 旅行

Description

给定平面上n个点,设计一条路线,从1号点出发,走到n号点在走回来,除了最左边的点,其他每个点恰好经过一次,且是的路径总长最短。两点之间的路径长度为欧几里得距离(就是直线距离)。

Solution

处理从1号点走到n号点在走回来的情况很复杂,所以我们可以假设有2个人一起走,并且走的点不重复。
f[i][j] 表示第一个人走到i,第二个人走到j的最优答案。但是这样还是不知道自己走的对方是否走过。
所以设 f[i][j] 表示1..i都走过,第一个人走到i,第二个人走到j的最优答案。
那么可能是第一个人走到i+1或是第二个人走到i+1。
所以转移变成了 f[i][j]f[i+1][j],f[i][j]f[i][i+1]
但这样还是有弊端。
N2 的空间很大,必须开滚动数组。假设i和j相差很大,不可能完成所有的转移。
所以强制i>j。
所以 f[i][j]f[i+1][i]f[i+1][j]
为什么这样是对的?
在进行点i+1的更新时,我们可以假想是哪个人选了第i+1个点。这个记录过程类似于背包。那么 f[i][j]f[j][i] 维护的是一样的东西。
所以可以强制i>j.

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 5010
#define DB double
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
DB f[2][N];
int i,j,k,l,n,o;
DB x[N],y[N];
DB dis(int a,int b){
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
int main(){
    scanf("%d",&n);
    fo(i,1,n) scanf("%lf%lf",&x[i],&y[i]);
    fo(j,1,n-1)
        f[o][j]=dis(n,n-1)+dis(n,j); 
    fd(i,n-2,2){
        o=1-o;
        fo(j,1,i-1)
            f[o][j]=min(f[1-o][j]+dis(i+1,i),f[1-o][i]+dis(i+1,j));
    }
    printf("%.4lf",f[o][1]+dis(1,2)); 
    return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值