UVA1347 旅行

UVA1347 旅行

题目大意

给定 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi),从最左边的点出发到达最右边,再返回最左边,要求经过的点不重复且覆盖所有的点,求最小路径长(两点的距离定义为欧几里得距离)

思路动态规划

题目要求从左到右再到左的路径长,可以转化成两个人同时从左边出发向右走,且路径不重叠
这样就可以确定状态 f i ,   j   ( i > j ) f_{i,~j} ~ (i \gt j) fi, j (i>j),表示其中一个人走到 i i i 点,另一个人走到了 j j j 点时的最短路径和
于是便有了状态转移方程:
f i ,   j + 1 = min ⁡ ( f i ,   j + 1 , f i ,   j + d i s j ,   j + 1 ) f_{i,~j+1}=\min(f_{i,~j+1},f_{i,~j}+dis_{j,~j+1}) fi, j+1=min(fi, j+1,fi, j+disj, j+1)
f j ,   j + 1 = min ⁡ ( f j ,   j + 1 , f i ,   j + d i s i ,   j + 1 ) f_{j,~j+1}=\min(f_{j,~j+1},f_{i,~j}+dis_{i,~j+1}) fj, j+1=min(fj, j+1,fi, j+disi, j+1)
第一个方程表示其中一个人从 j j j 转移到了 j + 1 j+1 j+1;第二个方程类似,表示的是从 i i i 转移到 j + 1 j+1 j+1
枚举时要注意顺序,因为题目中要求不能经过重复的点,因此在枚举 j+1 时要从 i+1 开始,这样可以避免枚举到 f i ,   i f_{i,~i} fi, i 的情况

Code
#include <cstdio> 
#include <cstring>
#include <cmath>
#include <algorithm> 
using namespace std;
const int maxn=1e3+7;
const double MAX=1e20;
int n;
double dis[maxn][maxn],f[maxn][maxn];
struct Point{
	double x,y;
	bool operator<(const Point& rhs)const {return x<rhs.x;}
}a[maxn];
int main(){
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
		sort(a+1,a+1+n);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				f[i][j]=MAX;	//赋初值为无穷大
				dis[i][j]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
				//预处理出每两个点之间的距离
			}
		}
		f[1][1]=0;
		for(int i=1;i<=n;i++){
			for(int j=i;j<=n;j++){
				//状态转移
				f[i][j+1]=min(f[i][j+1],f[i][j]+dis[j][j+1]);
				f[j][j+1]=min(f[j][j+1],f[i][j]+dis[i][j+1]);
			}
		}
		double ans=MAX;
		for(int i=1;i<=n;i++) ans=min(ans,f[i][n]+dis[i][n]);
		printf("%.2lf\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值