P1523 旅行商簡化版 題解
阿新 • • 發佈:2021-07-30
在確定方向後,這道題也就不再是 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)\)
在最後輸出 \(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; }