1. 题目解析与算法选择
这道经典的NOIP题目描述了一个地窖挖雷的场景,我们需要设计算法找到能挖到最多地雷的路径。题目给出的关键约束条件是:每次只能移动到编号比当前节点大且联通的节点。这个条件直接决定了我们可以采用哪些算法来解决这个问题。
1.1 题目关键特征分析
首先,我们需要明确几个关键特征:
- 有向无环图(DAG):由于只能往编号更大的节点移动,这意味着图中不可能存在环,且节点的编号天然构成了一个拓扑序。
- 小规模数据:N≤20,这个数据范围非常小,给了我们算法选择的灵活性。
- 路径记录要求:不仅需要计算最大地雷数,还需要记录具体的路径。
1.2 算法选择考量
基于上述特征,我们主要考虑两种解法:
-
动态规划(DP):
- 优势:利用DAG的特性,可以高效地计算出最优解
- 复杂度:O(N²),对于N=20来说非常高效
- 实现难度:中等,需要设计状态转移方程和路径记录机制
-
深度优先搜索(DFS):
- 优势:实现直观,适合小规模数据
- 复杂度:最坏情况下O(2^N),但N=20时约为百万级别,现代计算机可以轻松处理
- 实现难度:较低,但需要注意回溯和路径记录
提示:在实际编程竞赛中,如果时间允许,建议先实现DFS作为保底解法,再优化为DP解法。这样可以确保至少有一个可行的解法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态规划解法详解
动态规划是解决这类DAG上最优路径问题的标准方法。下面我们详细拆解DP解法的实现步骤。
2.1 状态定义与转移方程
我们定义两个核心数组:
dp[i]:表示以第i个地窖为终点时能挖到的最大地雷数pre[i]:记录到达第i个地窖的最优前驱节点
状态转移方程:
code复制dp[i] = max(dp[j] + a[i]) for all j < i and g[j][i] == 1
其中a[i]是第i个地窖的地雷数,g[j][i]表示j到i是否有路径。
2.2 实现步骤详解
-
初始化:
- 每个地窖的初始dp值为自身的地雷数
- 前驱数组pre初始化为自身
-
填表过程:
- 按编号顺序处理每个地窖
- 对于每个地窖i,检查所有编号比它小的地窖j
- 如果有路径(j,i),则尝试更新dp[i]
-
路径回溯:
- 找到dp值最大的地窖作为终点
- 利用pre数组逆向追踪路径
- 使用栈结构将路径反转成正序
2.3 完整代码实现
cpp复制#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
int main() {
int n;
int a[30]; // 地雷数量
int g[3
