E[u]
是一个邻接表,存储从节点u到其他节点的边。deg[i]
记录每个节点的入度,方便进行拓扑排序。f[u]
记录从节点u开始的所有可能路径的数量,用于判断第k条路径起点的选择。代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /**************************************************************** * Description: 2023_CSP_S_F01 * Author: Alex Li * Date: 2024-06-18 13:56:33 * LastEditTime: 2024-06-18 19:16:24 ****************************************************************/ #include <iostream> #include <algorithm> #include <vector> const int MAXN = 100000; // 定义最大节点数 const long long LTM = 1000000000000000000; // 定义一个很大的数,用于限制路径数量的上限 int n, m, deg[MAXN]; // n: 节点数, m: 边数, deg: 每个节点的入度数组 std::vector<int> E[MAXN]; // 邻接表存储图的边关系 long long k, f[MAXN]; // k: 要查找的第k小路径,f[i]: 从节点i开始的路径数量 // 在后选点中,找第k小的路径的起点 int next(std::vector<int> cand, long long &k) { std::sort(cand.begin(), cand.end()); // 对候选节点进行排序 for(int u : cand) { // 遍历排序后的候选节点 if(k <= f[u]) return u; // 如果k在当前节点u对应的路径数量范围内,返回u作为起点 k -= f[u]; // 否则减去该节点对应的路径数量,继续下一个候选节点 } return -1; // 如果找不到合适的节点,返回-1 } int main() { std::cin >> n >> m >> k; // 读入节点数n,边数m,和需要查询的第k小路径 for(int i = 0; i < m; ++i) { int u, v; std::cin >> u >> v; // 读入每条边的起点u和终点v E[u].push_back(v); // 将边添加到邻接表E中,表示从u到v有一条边 ++deg[v]; // 增加节点v的入度 } // 拓扑排序 std::vector<int> Q; // 存储拓扑排序的结果 for(int i = 0; i < n; ++i) if(!deg[i]) Q.push_back(i); // 将所有入度为0的节点加入队列Q for(int i = 0; i < n; ++i) { int u = Q[i]; // 依次处理拓扑序中的每个节点 for(int v : E[u]) { // 遍历该节点u的所有邻接节点v if(deg[v] == 1) // 如果邻接节点v的入度为1,说明v的前驱都已处理 Q.push_back(v); // 将v加入拓扑序队列 --deg[v]; // 减少节点v的入度 } } std::reverse(Q.begin(), Q.end()); // 将拓扑序逆序,方便后续动态规划计算路径数量 // 动态规划计算f(i): 从i节点开始的路径数量 for(int u : Q) { f[u] = 1; // 每个节点的路径数量初始为1(即单个节点本身) for(int v : E[u]) // 遍历该节点u的所有邻接节点v f[u] = std::min(f[u] + f[v], LTM); // 累加从v开始的路径数量,避免超过上限LTM } // 查找第k小的路径的起点 int u = next(Q, k); std::cout << u << std::endl; // 输出起点u // 如果需要依次找到第k-1, k-2的路径 while(k > 1) { --k; // 递减k u = next(E[u], k); // 查找当前节点u的邻接节点中第k小的路径 std::cout << u << std::endl; // 输出当前的节点 } return 0; } |