题解:学而思编程 汽车变速
【题目来源】
学而思编程:汽车变速
【题目描述】
小猴开着车通过某路段。路段的入口和出口设有测速装置,它们测量出,汽车在起点速度为 \(v_1\) 米/秒,终点速度为 \(v_2\) 米/秒,还知道小猴通过这段路用了 \(t\) 秒。
假设每秒内的速度恒定,在每秒之间,小猴可以改变汽车速度,但是由于汽车性能的限制,新的速度与之前速度的差值不能超过 \(d\)。
求这个路段的最大可能长度,单位为米。
【输入】
第一行包含两个整数 \(v_1\) 和 \(v_2\) 。
第二行包含两个整数 \(t\) 和 \(d\) 。
数据保证一定有解。
【输出】
仅有一个数,表示以米为单位的路段最大可能长度。
【输入样例】
5 6
4 2
【输出样例】
26
【核心思想】
-
问题分析:给定初始速度 \(v_1\)、终点速度 \(v_2\)、总时间 \(t\) 和每秒最大速度变化量 \(d\)。每秒内速度恒定,每秒之间速度变化不超过 \(d\)。求路段的最大可能长度。这是一个线性动态规划问题,关键在于在速度变化约束下,最大化每秒行驶距离之和。
-
算法选择:
- 动态规划(DP):
f[i][j]表示第 \(i\) 秒速度为 \(j\) 时,前 \(i\) 秒走过的最大总路程 - 状态转移:枚举前一秒的速度 \(k\),在速度变化允许范围内更新当前状态
- 动态规划(DP):
-
关键步骤:
- 状态定义:
f[i][j]表示第 \(i\) 秒速度为 \(j\) 时,前 \(i\) 秒的最大总路程 - 初始化:
memset(f, -0x3f, sizeof(f)),`f[1][v_1] = v_1$(第一秒速度为 \(v_1\),路程为 \(v_1\)) - 状态转移(枚举时间 \(i\) 从 \(2\) 到 \(t\)):
- 枚举第 \(i\) 秒的速度 \(j\)(范围 \([0, v_1 + (i-1) \times d]\))
- 枚举第 \(i-1\) 秒的速度 \(k\)(范围 \([\max(0, j-d), j+d]\))
f[i][j] = \max(f[i][j], f[i-1][k] + j)
- 结果:
f[t][v_2](第 \(t\) 秒速度恰好为 \(v_2\) 时的最大总路程)
- 状态定义:
-
时间/空间复杂度:
- 时间复杂度:\(O(t \cdot V \cdot d)\),其中 \(V = v_1 + (t-1) \cdot d\) 为最大可能速度。具体为三重循环:时间 \(t\)、速度 \(V\)、速度变化范围 \(2d+1\)
- 空间复杂度:\(O(t \cdot V)\),二维 DP 数组
-
线性DP的核心思想:
- 按时间线性递推:以时间为阶段,每一秒的状态只与前一秒有关
- 速度作为第二维状态:将速度约束转化为状态维度,确保每秒速度变化不超过 \(d\)
- 最大化路径和:每秒贡献当前速度值 \(j\),通过 DP 累加求最大总路程
- 边界条件处理:初始速度固定为 \(v_1\),终止速度固定为 \(v_2\)
- 适用于带约束的序列最优化问题
【算法标签】
线性DP-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// ================= 常量与全局变量 =================
const int N = 105; // 最大时间步数
const int M = 1105; // 最大速度值
int v1; // 初始速度
int v2; // 最终速度
int t; // 总时间
int d; // 每秒钟速度的最大变化量
int f[N][M]; // 动态规划数组
// f[i][j] 表示第 i 秒速度为 j 时,前 i 秒走过的最大总路程
// ================= 主函数 =================
int main()
{
// 读取初始速度、最终速度、总时间和最大加速度
cin >> v1 >> v2 >> t >> d;
// 初始化 dp 数组为极小值
memset(f, -0x3f, sizeof(f));
// 边界条件:第 1 秒速度为 v1,路程为 v1
f[1][v1] = v1;
// 动态规划递推
for (int i = 2; i <= t; i++) // 枚举时间步
{
// 第 i 秒的可能速度范围:[0, v1 + (i-1)*d]
for (int j = 0; j <= v1 + (i - 1) * d; j++)
{
// 第 i-1 秒的速度 k 必须在 [j-d, j+d] 范围内
// 即速度变化不能超过 d
for (int k = max(0, j - d); k <= j + d; k++)
{
// 转移:前 i-1 秒的路程 + 第 i 秒的路程 j
f[i][j] = max(f[i][j], f[i - 1][k] + j);
}
}
}
// 输出第 t 秒速度为 v2 时的最大总路程
cout << f[t][v2];
return 0;
}
【运行结果】
5 6
4 2
26
浙公网安备 33010602011771号