蜗牛
题目分析
第一个阶段定义dp数组
(1)缩小规模。我们要从第1根竹竿爬到第n根竹竿,那么规模就是这n根竹竿,dp[i]表示当前爬到了第i根竹竿。
(2)考虑限制。
限制1,只能在x轴或者竹竿上爬行,在x轴上爬行速度为1单位每秒,在竹竿上向上和向下爬行的速度分别为0.7单位每秒和1.3单位每秒。
限制2,在第i和第i+1个竹竿间有传送门,可以由第i根竹竿高度为 a i a_i ai的位置 ( x i , a i ) (x_i,a_i) (xi,ai),瞬移到第i+1根竹竿高度为 b i + 1 b_{i+1} bi+1的位置 ( x i + 1 , b i + 1 ) (x_{i+1},b_{i+1}) (xi+1,bi+1)。
对于一个蜗牛的在第i根竹竿上的位置有两种状态,要么是从x轴爬过来的,此时高度为0,要么是从第i-1个竹竿瞬移过来的,此时高度为 b i b_i bi。需要一个状态表示此时蜗牛处在哪个位置,所以 d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示从x轴爬过来的,此时高度为0, d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示从第i-1个竹竿瞬移过来的,此时高度为 b i b_i bi。
(3)定义dp数组
d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示从x轴爬过来的,此时高度为0,花费的时间。
d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示从第i-1个竹竿瞬移过来的,此时高度为 b i b_i bi,花费的时间。
第二个阶段推导状态转移方程
d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] + x [ i ] − x [ i − 1 ] , d p [ i − 1 ] [ 1 ] + b [ i ] / 1.3 ) dp[i][0]=min(dp[i-1][0]+x[i]-x[i-1],dp[i-1][1]+b[i]/1.3) dp[i][0]=min(dp[i−1][0]+x[i]−x[i−1],dp[i−1][1]+b[i]/1.3)
d p [ i − 1 ] [ 0 ] + x [ i ] − x [ i − 1 ] dp[i-1][0]+x[i]-x[i-1] dp[i−1][0]+x[i]−x[i−1]表示是从第i-1个竹竿从x轴爬过来的,那么消耗的时间就是x轴上的距离 x [ i ] − x [ i − 1 ] x[i]-x[i-1] x[i]−x[i−1]。
d p [ i − 1 ] [ 1 ] + b [ i ] / 1.3 dp[i-1][1]+b[i]/1.3 dp[i−1][1]+b[i]/1.3表示是从第i-1个竹竿从x轴瞬移过来的,瞬移到高度为b[i]的地方,那么我要从那个地方下来,那么消耗的时间就是从y轴下来的距离 b [ i ] / 1.3 b[i]/1.3 b[i]/1.3。
i f ( a [ i ] > b [ i ] ) if(a[i]>b[i]) if(a[i]>b[i]),如果是瞬移过来的,我要向上爬。
d p [ i ] [ 1 ] = m i n ( d p [ i ] [ 0 ] + a [ i ] / 0.7 , d p [ i − 1 ] [ 1 ] + ( a [ i ] − b [ i ] ) / 0.7 ) dp[i][1]=min(dp[i][0]+a[i]/0.7,dp[i-1][1]+(a[i]-b[i])/0.7) dp[i][1]=min(dp[i][0]+a[i]/0.7,dp[i−1][1]+(a[i]−b[i])/0.7)
i f ( a [ i ] < b [ i ] ) if(a[i]<b[i]) if(a[i]<b[i]),如果是瞬移过来的,我要向下爬。
d p [ i ] [ 1 ] = m i n ( d p [ i ] [ 0 ] + a [ i ] / 0.7 , d p [ i − 1 ] [ 1 ] + ( b [ i ] − a [ i ] ) / 1.3 ) dp[i][1]=min(dp[i][0]+a[i]/0.7,dp[i-1][1]+(b[i]-a[i])/1.3) dp[i][1]=min(dp[i][0]+a[i]/0.7,dp[i−1][1]+(b[i]−a[i])/1.3)
第三个阶段写代码
(1)dp数组的初始化
从(0,0)处开始爬,爬到第一个竹竿和第一个竹竿传送门处的耗时如下。
java
double[][] dp = new double[n + 1][2];
dp[1][0] = x[1]; // 底端最小用时
dp[1][1] = x[1] + a[1] / 0.7; // 传送门用时
(2)递推dp数组
a.第一层for循环表示的是规模
c.第二层for循环表示的是dp数组的转移点 只有两个,不需要用for循环
(3)表示答案
d p [ n ] [ 0 ] dp[n][0] dp[n][0]
题目代码
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] x = new int[n+1];
int[] a = new int[n+1];
int[] b = new int[n+1];
for(int i = 1;i<=n;i++){
x[i] = sc.nextInt();
}
for(int i = 1;i<n;i++){
a[i] = sc.nextInt();
b[i+1] = sc.nextInt();
}
double[][] dp = new double[n+1][2];
dp[1][0] = x[1];
dp[1][1] = x[1] + a[1]/0.7;
for(int i = 2;i <= n;i++){
dp[i][0] = Math.min(dp[i-1][1] +b[i]/1.3 ,dp[i-1][0]+x[i]-x[i-1]);
if(a[i]>b[i]){
dp[i][1] = Math.min(dp[i][0] + a[i]/0.7, dp[i-1][1] + (a[i]-b[i])/0.7);
}else {
dp[i][1] = Math.min(dp[i][0] + a[i]/0.7,dp[i-1][1] + (b[i]-a[i]) /1.3);
}
}
System.out.printf("%.2f",dp[n][0]);
sc.close();
}
}