1 条题解
-
0
分析:
本题要找出到达第 n 个检查点的最短时间,可将其拆分为到达每个检查点的子问题。通过考虑在不同的前序检查点更换轮胎,计算出到达每个检查点的最短时间,最终得到到达第 n 个检查点的最短时间。
解题原理
核心算法思想是动态规划。通过定义状态 dp[i] 表示到达第 i 个检查点的最短时间,利用子问题的最优解来推导当前问题的最优解。在计算 dp[i] 时,枚举所有可能的前一个检查点 j,计算从 j 到 i 的行驶时间,加上到达 j 的最短时间以及可能的换轮胎时间,取最小值作为 dp[i] 的值。
实现步骤
1.预计算时间表:根据不同距离和速度规则,预先计算出从起点到每个距离的行驶时间,存储在 time_table 数组中。
2.初始化动态规划数组:将 dp 数组初始化为一个很大的值,dp[0] 设为 0,表示起点的时间为 0。
3.动态规划计算:
1.遍历每个检查点 i(从 1 到 n)。
2.对于每个 i,枚举所有可能的前一个检查点 j(从 0 到 i - 1)。
3.计算从 j 到 i 的行驶时间,通过 time_table 数组直接获取。
4.计算到达 i 的总时间,包括到达 j 的最短时间、从 j 到 i 的行驶时间以及可能的换轮胎时间。
5.更新 dp[i] 为所有可能路径中的最小值。
4.输出结果:输出 dp[n],即到达第 n 个检查点的最短时间。
c++代码:
#include <stdio.h> #define MAX_N 110 #define MAX_DIST 10010 double dp[MAX_N]; // dp[i] 表示到达第 i 个检查点的最短时间 int a[MAX_N]; // 检查点距离 double time_table[MAX_DIST]; // 预计算的时间表 int n; double b, r, v, e, f; // 预计算时间表 void precompute_time_table(int max_dist) { time_table[0] = 0.0; for (int i = 1; i <= max_dist; i++) { double denominator; if (i - 1 >= r) { denominator = v - e * ((i - 1) - r); } else { denominator = v - f * (r - (i - 1)); } if (denominator < 1e-6) { fprintf(stderr, "分母过小,可能导致计算异常,程序终止。\n"); return; } if (i - 1 >= r) { time_table[i] = time_table[i - 1] + 1.0 / (v - e * ((i - 1) - r)); } else { time_table[i] = time_table[i - 1] + 1.0 / (v - f * (r - (i - 1))); } } } void solve() { // 初始化 dp 数组 for (int i = 0; i <= n; i++) { dp[i] = 1e20; // 初始化为很大的值 } dp[0] = 0.0; // 起点时间为 0 // 动态规划计算最优解 for (int i = 1; i <= n; i++) { for (int j = 0; j < i; j++) { // 从 j 到 i 不换轮胎的距离 int dist = a[i - 1] - (j == 0 ? 0 : a[j - 1]); // 直接查表获取行驶时间 double segment_time = time_table[dist]; // 如果 j > 0,需要考虑换轮胎时间 b double total_time = dp[j] + segment_time + (j > 0 ? b : 0); if (total_time < dp[i]) { dp[i] = total_time; } } } printf("%.4f\n", dp[n]); } int main() { while (scanf("%d", &n) == 1 && n != 0) { if (n < 1 || n > MAX_N) { fprintf(stderr, "检查点数量n超出合法范围,程序终止。\n"); return 1; } // 读取检查点距离 for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } // 读取其他参数 scanf("%lf", &b); scanf("%lf", &r); scanf("%lf", &v); scanf("%lf", &e); scanf("%lf", &f); if (a[n - 1] >= MAX_DIST) { fprintf(stderr, "检查点距离超过预定义的最大距离,程序终止。\n"); return 1; } precompute_time_table(a[n - 1]); solve(); } return 0; }
- 1
信息
- ID
- 1744
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 10
- 已通过
- 2
- 上传者