(寒假马拉松 第一场 J题)
dps[i][j]代表走的快的人到达i,走的慢的人到达j时的最小距离。
当连接新的点i+1时,如果给j,则j就超过了i,成为了更快的人,下一状态变成dp[i+1][i]。
如果给i,给j保持不变,下一状态为dp[i+1][j]。
由此得到递推公式:
dps[i+1][i] = min(dps[i+1][i], dps[i][j] + dis(j, i+1));
dps[i+1][j] = min(dps[i+1][j], dps[i][j] + dis(i, i+1));
由于最右节点必然是终点,所以走的快的人必然到达了n-1点,最终的距离就是枚举j,dps[n-1][j] + dis(j, n-1)中最小的。
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int N=100; const double X=1e100;//1e100 1乘以10的100次方 double dps[N][N]; int x[N],y[N]; double dis(int x1,int y1,int x2,int y2){ return sqrt(1.0*(x1-x2)*(x1-x2)+1.0*(y1-y2)*(y1-y2)); } double dis(int i,int j){ return dis(x[i],y[i],x[j],y[j]); } double min(double x,double y){ return x<y?x:y; } int main(){ int n; while(~scanf("%d",&n)){ int i,j; for(i=0;i<n;i++){ scanf("%d%d",&x[i],&y[i]); //printf("%d %d",x[i],y[i]); for(j=0;j<n;j++) dps[i][j]=X; } //puts(""); dps[1][0]=dis(1,0); for(i=0;i<n-1;i++) for(j=0;j<i;j++){ dps[i+1][i]=min(dps[i+1][i],dps[i][j]+dis(j,i+1)); dps[i+1][j]=min(dps[i+1][j],dps[i][j]+dis(i,i+1)); } double ans=X; for(j=0;j<n-1;j++){ ans=min(ans,dps[n-1][j] + dis(j,n-1)); //printf("%.2lf ",ans); } printf("%.2f\n",ans); } return 0; }