📅  最后修改于: 2023-12-03 15:12:14.295000             🧑  作者: Mango
本题是GATE CS 1998考试中的第25个问题,涉及到数据结构和算法问题。本题目的是要求程序员实现一个函数,在一个给定的有向无环图(DAG)中计算所有从源节点到目标节点的路径的总数。
给定一个有向无环图(DAG)$G = (V, E)$,其中 $V$ 是节点集合,$E$ 是边集合。每个节点都由唯一的标识符 $id$ 表示。
假设我们有两个顶点 $s$ 和 $t$,分别表示图的起始节点和结束节点。现在要求实现一个函数 countPaths(Graph g, int s, int t)
,该函数计算从 $s$ 到 $t$ 的所有路径数量。如果不存在这样的路径,则函数应该返回 0。
函数的输入参数是一个有向无环图 $g$,由适当的数据结构表示。每个节点都由唯一的标识符 $id$ 表示。此外,输入还包括起始节点 $s$ 和目标节点 $t$ 的标识符。
函数应该输出从 $s$ 到 $t$ 的所有路径数量。如果不存在这样的路径,则函数应该返回 0。
这是一道经典的动态规划问题。要计算从 $s$ 到 $t$ 的所有路径数量,我们可以定义一个长度为 $n$ 的数组 $count$,其中 $n$ 表示图中的节点数。对于任何节点 $u$,$count[u]$ 表示从 $u$ 到 $t$ 的所有路径数量。
现在我们考虑如何填充 $count$ 数组。为此,我们可以按照拓扑排序的顺序处理图中的所有节点。假设当前处理的节点是 $u$,那么我们可以遍历 $u$ 的所有直接后继 $v$,并为每个 $v$ 维护一个计数器 $count[v]$。我们可以将 $count[u]$ 的值更新为 $v$ 的计数器之和,即:
$$ count[u] = \sum\limits_{v \in succ(u)} count[v] $$
最终,当我们完成拓扑排序后,$count[s]$ 的值就是从 $s$ 到 $t$ 的所有路径数量。
下面是一个Java代码片段实现了上述算法。
import java.util.*;
public class Graph {
private int n;
private List<Integer>[] adj;
public Graph(int n) {
this.n = n;
adj = new List[n];
for (int u = 0; u < n; u++) {
adj[u] = new ArrayList<>();
}
}
public void addEdge(int u, int v) {
adj[u].add(v);
}
public int countPaths(int s, int t) {
int[] count = new int[n];
count[t] = 1;
for (int u : topologicalSort()) {
for (int v : adj[u]) {
count[u] += count[v];
}
}
return count[s];
}
private List<Integer> topologicalSort() {
int[] inDegree = new int[n];
for (int u = 0; u < n; u++) {
for (int v : adj[u]) {
inDegree[v]++;
}
}
Queue<Integer> queue = new LinkedList<>();
for (int u = 0; u < n; u++) {
if (inDegree[u] == 0) {
queue.offer(u);
}
}
List<Integer> res = new ArrayList<>();
while (!queue.isEmpty()) {
int u = queue.poll();
res.add(u);
for (int v : adj[u]) {
inDegree[v]--;
if (inDegree[v] == 0) {
queue.offer(v);
}
}
}
return res;
}
}