P1523 旅行商简化版 题解
在确定方向后,这道题也就不再是 NPC 问题了,而是询问从一个起点出发的,具有相同终点的两条路径的最小总长度。由此想到 DP 做法,且与 P1006 有相像之处。
不妨设 f[i][j] 为一个点走到 i 位置,一个点走到 j 位置(由于 f[i][j]=f[j][j],所以不妨令 i>j)时,两点距离终点的最短距离。
但是如果一个人往 i+2 走,中间会少 i+1 这个点没被走过,无法表示成状态。那么我们可以限制只让走 i+1 来解决这一问题。
由此有状态转移方程:
f_{x,y}=\min(f_{x+1,y}+dis(x,x+1),f_{x,x+1}+dis(y,x+1))
其中 dis(x,y) 指点 x 与 y 的距离,用公式 \sqrt{x^2+y^2} 计算。
在最后输出 f_{2,1}+dis(1,2) 即可。
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
#define ri register int
#define il inline
const int INF=0x7fffffff,N=1e3+10;
int n;
double d1,d2;
double f[N][N];
struct pts{
double x,y;
}p[N];
il ll read(){
ll x=0,y=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
y=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*y;
}
il bool cmp(pts x,pts y){
return x.x<y.x;
}
il double dis(double x_1,double y_1,double x_2,double y_2){
return sqrt((x_1-x_2)*(x_1-x_2)+(y_1-y_2)*(y_1-y_2));
}
signed main(){
n=read();
for(ri i=1;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p+1,p+n+1,cmp);
d1=dis(p[n].x,p[n].y,p[n-1].x,p[n-1].y),d2=dis(p[1].x,p[1].y,p[2].x,p[2].y);
for(ri i=1;i<=n-2;i++)
f[n-1][i]=dis(p[n].x,p[n].y,p[i].x,p[i].y)+d1;
for(ri i=n-2;i>=2;i--){
for(ri j=1;j<i;j++){
f[i][j]=f[i+1][j]+dis(p[i].x,p[i].y,p[i+1].x,p[i+1].y);
f[i][j]=min(f[i][j],f[i+1][i]+dis(p[j].x,p[j].y,p[i+1].x,p[i+1].y));
}
}
printf("%.2lf",f[2][1]+d2);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步