P1137 旅行计划
解题思路
这道题目要求我们为每个城市i计算以i为终点的最长路径长度。由于题目中给出的道路方向表示城市x在城市y的西面(即x→y是有向边),所以可以将城市和道路建模为一个有向无环图(DAG)。在这种情况下,最长路径问题可以通过拓扑排序结合动态规划来解决。
关键点
-
拓扑排序:由于图是有向无环图,可以使用拓扑排序来确定节点的处理顺序,确保在处理一个节点时,所有指向它的节点都已经被处理过。
-
动态规划:定义f[i]表示以城市i为终点的最长路径长度。初始时,每个城市的f[i]为1(至少包含自己)。对于每条边x→y,更新f[y] = max(f[y], f[x] + 1),表示如果从x到y的路径更长,则更新y的最长路径。
-
输入处理:读取道路信息时,需要记录每个节点的入度(rd数组),并在拓扑排序中使用这些入度信息来确定处理顺序。
注意事项
-
图的存储使用邻接表。
-
需要初始化每个节点的f[i]为1,因为每个节点至少可以单独作为一个路径。
-
拓扑排序时,使用队列来维护当前入度为0的节点,确保按正确的顺序处理节点。
代码注释
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; // 定义最大节点数 vector<int> g[N]; // 邻接表,存储有向图的边关系 int n, m; // n表示城市数量,m表示道路数量 int rd[N]; // 存储每个节点的入度 int f[N]; // f[i]表示以城市i为终点的最长路径长度 // 拓扑排序函数,用于计算每个节点的最长路径长度 void topsort() { queue<int> q; // 使用队列来维护当前入度为0的节点 for(int i = 1; i <= n; i++) { if(rd[i] == 0){ q.push(i); // 将入度为0的节点加入队列 } f[i] = 1; // 初始化每个节点的最长路径长度为1(至少包含自己) } while(q.size()) // 当队列不为空时,继续处理 { int x = q.front(); q.pop(); // 取出队首节点 for(int i = 0; i < g[x].size(); i++) // 遍历所有从x出发的边 { int y = g[x][i]; // y是x的后继节点 rd[y]--; // 减少y的入度 if(rd[y] == 0) q.push(y); // 如果y的入度为0,加入队列 f[y] = max(f[y], f[x] + 1); // 更新y的最长路径长度 } } } int main() { cin >> n >> m; // 输入城市数量和道路数量 for(int i = 1; i <= m; i++) { int x, y; cin >> x >> y; // 输入道路信息 rd[y]++; // 增加y的入度 g[x].push_back(y); // 添加有向边x→y } topsort(); // 执行拓扑排序和动态规划 for(int i = 1; i <= n; i++) cout << f[i] << endl; // 输出每个城市的最长路径长度 return 0; }

浙公网安备 33010602011771号