1 条题解
-
0
好的,我来分析一下这段代码,然后给出题解和算法标签。
代码分析
1. 问题理解
- 有 棵树排成一行,每棵树有高度
- 小鸟从第 1 棵树飞到第 棵树
- 每次可以飞 到 棵树的距离
- 从较低或等高的树飞到更高或等高的树会疲惫(计数+1)
- 目标:最小化疲惫次数
2. 算法核心 - 单调队列优化 DP
状态定义
f[i]表示飞到第 棵树的最小疲惫次数。状态转移
f[i] = f[dq[hd]] + (d[i] >= d[dq[hd]]);从队列头部的最优决策树
dq[hd]飞到第 棵树:- 如果 ,疲惫次数+1
- 否则,疲惫次数不变
单调队列维护
// 维护队列范围 if (i - dq[hd] > k) hd++; // 插入新元素 if (d[i] < d[dq[hd]]) { while (hd <= tl && d[dq[tl]] <= d[i]) tl--; dq[++tl] = i; }队列保持:
- 范围有效性:队首元素在 步范围内
- 单调性:队尾到队首,树高递减(保证队首是最优决策)
算法标签
基于代码分析,主要算法标签包括:
- 动态规划 (Dynamic Programming)
- 单调队列优化 (Monotonic Queue Optimization)
- 滑动窗口最值 (Sliding Window Maximum/Minimum)
- 最优化问题 (Optimization Problem)
题解
「XXI Olimpiada Informatyczna」小鸟 题解
题目分析
小鸟需要从第 1 棵树飞到第 棵树,每次最多飞 棵树的距离。从较低树飞到较高或等高的树会感到疲惫,目标是最小化疲惫次数。
关键观察
- 最优子结构:到达第 棵树的最小疲惫次数,可以由前面 棵树中的某棵转移而来
- 决策单调性:如果从树 飞到树 不会增加疲惫(),那么树 是比后面更高树更好的决策点
- 滑动窗口:对于每个位置 ,只需要考虑前 棵树作为可能的起点
算法思路
动态规划 + 单调队列优化
状态定义
设
f[i]表示飞到第 棵树的最小疲惫次数。状态转移
对于每个位置 :
f[i] = min{ f[j] + (d[i] >= d[j]) },其中 i-k ≤ j < i单调队列优化
使用双端队列维护可能的最优决策:
-
队列性质:
- 按树高递减排列
- 所有元素在当前位置的 步范围内
-
队列操作:
- 出队首:当队首元素超出 步范围时
- 出队尾:当新树比队尾树矮时,队尾不可能成为未来最优决策
- 入队:新树如果比队首树矮,加入队列
-
决策选择:
- 总是选择队首作为当前最优决策
- 如果飞到更高树,疲惫计数+1
算法步骤
int solve(int k) { 初始化队列,加入第1棵树 for i = 2 to N: // 维护队列范围 if (i - 队首 > k) 队首出队 // 计算f[i] f[i] = f[队首] + (d[i] >= d[队首]) // 维护队列单调性 if (d[i] < d[队首]) { while (队尾树高 ≤ d[i]) 队尾出队 将i加入队尾 } return f[N] }复杂度分析
- 时间复杂度: 每个元素最多入队出队一次
- 空间复杂度: 存储队列和DP数组
- 查询处理:,但由于 ,总复杂度可接受
算法正确性
该算法正确性的保证:
- 最优性:队列始终保持当前最优决策
- 单调性:队列按树高递减,确保矮树优先
- 完整性:考虑所有可能的转移
样例验证
样例输入
9 4 6 3 6 3 7 2 6 5 2 2 5输出:
2、1分析:
- 时,路径 1→3→5→7→8→9,疲惫2次
- 时,路径 1→6→9,疲惫1次
总结
本题通过单调队列优化动态规划,高效解决了带约束的最短路径问题。算法利用决策单调性将复杂度从 优化到 ,能够处理大规模数据。
最终算法标签:
动态规划单调队列滑动窗口最优化
- 1
信息
- ID
- 5149
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者