一道DP题
要求求出从原点开始到第N根柱子(竹竿)的底部的最短时间
所以我们要设置一个DP数组 dp[i]表示到第i根柱子底部的最短时间
以到第三根柱子底部的最短时间为例子
我们发现有两种方法可以到达第三根柱子的底部
第一种,从出发点1 开始走第二根柱子的传送门,传送到第三根柱子的相应位置pre然后从pre走到第三根柱子底部;
第二种,从第二根柱子的底部直接过来第三根柱子的底部 ;
考虑第一种方法的原因在于 如果两根柱子离得非常远 比如距离为10000,而走传送门在柱子上移动的距离只有10,远小于直接走X轴
考虑第二种方法的原因在于 有可能两柱子离得非常近 比如在x轴的距离为1 ,传送门却非常高,比如传送门高度10000;因此直接从底下走过去更快

因此实际上我们需要计算出到第i根柱子的底部的最短时间,实际上需要到第i-1根柱子的传送门的最短时间,和到第i-1根柱子底部的最短时间两个数据
分别记作dp[i-1][0],dp[i-1][1]
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
int n;
struct node{
double cur;
double nxt;
double pre;
double x;
};
double dp[N][2];
node a[N];
int main(){
cin>>n;
for(int i = 1 ; i<=n;i++){
cin>>a[i].x ;
}
for(int i = 1;i<n;i++){
cin>>a[i].cur ; //当前柱子的传送门位置
cin>>a[i].nxt ; //传送到下一根柱子的位置
a[i].pre = a[i-1].nxt ; //被上一根柱子传送过来的出口
}
a[0].x = 0;
a[0].cur = 0;
a[n].cur = a[n-1].nxt ;
a[n].pre = a[n-1].nxt ;
dp[0][1] = 0;
dp[0][0] = 1e8;
for(int i = 1 ; i <= n;i++)
{
double add1 ; //上个传送门传过来 再走到当前传送门
//传送门有可能在上一个柱子出口的上面 也可能在出口的下面
if(a[i].cur > a[i].pre ){
add1 = (a[i].cur - a[i].pre)/((0.7)*1.0) ;
}else if(a[i].cur <= a[i].pre ){
add1 = (a[i].pre - a[i].cur)/((1.3)*1.0) ;
}
double timecur1 = dp[i-1][0] + add1;
///到上个柱子传送门的最短时间 + 被传送出来后走到当前柱子传送门的时间
double line11 = dp[i-1][1];
double line12 = a[i].x - a[i-1].x ; //右
double line13 = a[i].cur /((0.7)*1.0); //上
double timecur2 = line11 + line12 +line13 ;
/// 在上个柱子底部的最短时间 + 走到第i根柱子再上传送门
dp[i][0] = min(timecur1,timecur2); //到当前柱子传送门最短时间
double timedown1 = dp[i-1][1] + a[i].x - a[i-1].x; //从上个柱子底直接走到这个柱子底部
double line22 = a[i].pre/((1.3)*1.0); //从传送门下到柱子底部
double timedown2 = dp[i-1][0] + line22;
dp[i][1] = min(timedown1,timedown2);//到当前柱子底最短时间
}
printf("%.2lf",dp[n][1]);
return 0;
}