洛谷P1137题解:拓扑排序与动态规划求解城市游览问题
一、题目解读
洛谷P1137题目要求解决一个基于有向图的旅行计划问题:给定N个城市和M条单向道路,每个城市可游览一次,求每个城市最多能游览多少个连续城市(包括自身)。问题本质是寻找拓扑排序下的最长路径,需利用图论算法与动态规划思想。
二、解题思路
核心思路是将问题转化为拓扑排序与动态规划的结合:
1. 构建有向图:用邻接表存储道路信息,记录每个节点的入度。
2. 拓扑排序:优先处理入度为0的节点,确保遍历顺序正确。
3. 动态规划更新:在拓扑排序过程中,每个节点的最大游览数由其前驱节点的最大值+1决定。
三、解题步骤
1. 输入与初始化:读取N、M,构建邻接表graph与入度数组inDegree,初始化dp数组为1(每个城市至少游览自己)。
2. 入度处理:将入度为0的节点加入队列q,作为拓扑排序起点。
3. 拓扑排序循环:
○ 弹出队首节点u,遍历其邻居v。
○ 更新dp[v] = max(dp[v], dp[u] + 1),记录最长路径。
○ 若v的入度减为0,则加入队列继续处理。
4. 输出结果:遍历dp数组输出每个城市的最长游览数。
四、代码与注释
#include <iostream> #include <queue> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; // 构建图的邻接表表示 vector<vector<int>> graph(N + 1); // 1-based索引 vector<int> inDegree(N + 1, 0); // 记录每个节点的入度 // 读取道路信息并构建图 for (int i = 0; i < M; ++i) { int x, y; cin >> x >> y; graph[x].push_back(y); // x -> y 的有向边 inDegree[y]++; // y的入度增加 } // 初始化拓扑排序队列 queue<int> q; vector<int> dp(N + 1, 1); // 每个城市至少能游览自己 // 将入度为0的节点加入队列 for (int i = 1; i <= N; ++i) { if (inDegree[i] == 0) { q.push(i); } } // 拓扑排序 while (!q.empty()) { int u = q.front(); q.pop(); // 遍历u的所有邻居 for (int v : graph[u]) { // 更新v的最大游览城市数 dp[v] = max(dp[v], dp[u] + 1); // 减少v的入度,如果入度为0则加入队列 if (--inDegree[v] == 0) { q.push(v); } } } // 输出结果 for (int i = 1; i <= N; ++i) { cout << dp[i] << endl; } return 0; }
五、总结
该解法巧妙利用拓扑排序保证遍历顺序,结合动态规划实时更新最优解,时间复杂度为O(N+M),适用于有向无环图(DAG)场景。掌握拓扑排序与动态规划的协同应用,可高效解决此类路径优化问题。
原创内容 转载请注明出处