UVA—1347 (经典动态规划)Tour
原题链接: https://vjudge.net/problem/UVA-1347/origin
测试样例
Sample Input
3
1 1
2 3
3 1
4
1 1
2 3
3 1
4 2
Sample Output
6.47
7.89
题意: 给定你 n n n个横坐标 x x x,递增的点。需要你设计一条最短欧几里得距离路线,要求从最左边的点出发,走到最右边的点之后再返回,且除了最左边的点和最右边的点之外的每个点都只走了一次。
解题思路: 这道题是一道经典的动态规划题目。如果我们按题目意思去思考那很难解决,因为不同时考虑无法确定全局最短。那么我们可以这样想,假设有两个人都是从最左边点出发,再走不同的路到达最右边的点。 既然是动态规划的题目,我们可以试着去描述状态,如果我们用 d p ( i , j ) dp(i,j) dp(i,j)表示第一个人走到第 i i i个点,第二个人走到第 j j j个点的目前最短距离。那么这个状态好像是可行的,但我们很难保证 i i i和 j j j不相等。那么我们再考虑一下,这两个人在走的过程中肯定是有一个人落后的,而这个状态是一直存在的,而如果我们再限制一下,如果领先的那个人到达第 i i i个点,而落后的那个人到达了第 j j j个点( i > j i>j i>j),那么能够保证的是前 i i i个点一定都走完了 (若前 i i i个点没有走完,那么剩下的点也依旧是要落后的那个人走完,否则条件不成立,所有这个一定满足。) 所以我们可以定义状态为 d p ( i , j ) ( i > j ) dp(i,j)(i>j) dp(i,j)(i>j)表示前 i i i个点已经走完且落后的那个人在第 j j j个点。那么接下来第 i + 1 i+1 i+1个点就有人要走了,可以是落后的那个人,也可以是领先的那个人。故我们状态转移方程即可写为:
- d p ( i + 1 , i ) = m i n ( d p ( i + 1 , i ) , d p ( i , j ) + d i s t ( i , j ) ) ( 1 < j < i ) dp(i+1,i)=min(dp(i+1,i),dp(i,j)+dist(i,j))(1<j<i) dp(i+1,i)=min(dp(i+1,i),dp(i,j)+dist(i,j))(1<j<i)
- d p ( i + 1 , j ) = m i n ( d p ( i + 1 , j ) , d p ( i , j ) + d i s t ( i , i + 1 ) ) ( 1 < j < i ) dp(i+1,j)=min(dp(i+1,j),dp(i,j)+dist(i,i+1))(1<j<i) dp(i+1,j)=min(dp(i+1,j),dp(i,j)+dist(i,i+1))(1<j<i)
那么随着状态转移边界边界即是 d p ( n , j ) ( 1 < j < n ) dp(n,j)(1<j<n) dp(n,j)(1<j<n),那么也就是说前 n n n个点都已经走完了,且落后的那个人在 j j j点。那么我们还需要加上这段距离并取最优值。具体看AC代码。
AC代码
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e3;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
struct point{
double x,y;
};
point points[maxn];
double dp[maxn][maxn];
double dist(int a,int b){
double dx=fabs(points[a].x-points[b].x);
double dy=fabs(points[a].y-points[b].y);
return sqrt(dx*dx+dy*dy);
}
int n;
void solve(){
rep(i,1,n){
rep(j,1,n){
dp[i][j]=(1LL<<60);
}
}
dp[1][1]=0,dp[2][1]=dist(1,2);
rep(i,1,n-1){
rep(j,1,i-1){
//j代表落后点,当然也可以改变角色超前。
//接下来是继续以j为落后点还是以i为落后点。
dp[i+1][i]=min(dp[i+1][i],dp[i][j]+dist(i+1,j));
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+dist(i,i+1));
}
}
double result=1LL<<60;
rep(i,1,n-1){
result=min(result,dp[n][i]+dist(i,n));
}
printf("%.2f\n",result);
}
int main(){
while(cin>>n){
rep(i,1,n){
cin>>points[i].x>>points[i].y;
}
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!