📜  门| GATE-CS-2015(模拟测试)|问题2(1)

📅  最后修改于: 2023-12-03 15:42:18.132000             🧑  作者: Mango

GATE-CS-2015(模拟测试)|问题2

这道题目是关于图(Graph)的基本操作和算法。

题目描述

给定一个有向无环图(DAG),这个图有$n$个节点,我们要对这个图进行以下操作:

  1. 给定一个节点$s$,要求找到从节点$s$出发可以到达的所有节点。
  2. 给定两个节点$s$和$t$,要求找到从节点$s$到节点$t$的所有路径。
解题思路

对于这道题目,我们可以使用深度优先搜索(DFS)和拓扑排序(Topological Sort)来解决。

方法一:DFS

对于操作1,我们可以从节点$s$开始深度优先遍历整个图,记录所有可以到达的节点。在遍历时,我们可以使用一个布尔型数组$visited$来记录每一个节点是否已经被访问过。

对于操作2,我们可以从节点$s$开始深度优先遍历整个图,记录所有路径。在遍历时,我们可以使用一个栈$stack$来保存走过的路径,每次发现目标节点$t$时,将栈中的路径记录下来。

这种方法的时间复杂度为$O(n+m)$,其中$m$为边的数量。

方法二:拓扑排序

对于操作1和操作2,我们可以使用拓扑排序来解决。

对于操作1,我们可以先对图进行拓扑排序,然后从节点$s$开始向下遍历,将所有没有出边的节点依次加入到答案中,如果遇到一个节点存在出边,则把它的所有出边指向的节点加入到答案中。这样我们就可以得到所有可以到达的节点集合。

对于操作2,我们可以先对图进行拓扑排序,然后使用动态规划的思想进行求解。我们可以使用一个$dp[i]$数组表示从节点$s$到节点$i$的所有路径,初始化为一个空的二维数组。然后对于两个相邻的节点$i$和$j$,如果存在一条从$i$到$j$的边,那么我们就可以将$dp[j]$数组中的所有路径加上$i$到$j$的这条边,具体的操作可以采用类似DFS的方法。

这种方法的时间复杂度为$O(n+m)$,其中$m$为边的数量。

伪代码
方法一:DFS

操作1

def dfs1(node, visited, graph, ans):
    visited[node] = True
    ans.add(node)
    for next_node in graph[node]:
        if not visited[next_node]:
            dfs1(next_node, visited, graph, ans)

def get_reachable_nodes_dfs(s, graph):
    n = len(graph)
    visited = [False]*n
    ans = set()
    dfs1(s, visited, graph, ans)
    return ans

操作2

def dfs2(node, visited, graph, stack, ans, t):
    visited[node] = True
    stack.append(node)
    if node==t:
        ans.append(stack.copy())
    else:
        for next_node in graph[node]:
            if not visited[next_node]:
                dfs2(next_node, visited, graph, stack, ans, t)
    stack.pop()
    visited[node] = False

def get_all_paths_dfs(s, t, graph):
    n = len(graph)
    visited = [False]*n
    stack = []
    ans = []
    dfs2(s, visited, graph, stack, ans, t)
    return ans
方法二:拓扑排序

操作1

def get_reachable_nodes_topo(s, graph):
    n = len(graph)
    indegree = [0]*n
    ans = set()
    for i in range(n):
        for j in graph[i]:
            indegree[j] += 1
    q = [s]
    while q:
        node = q.pop()
        ans.add(node)
        for next_node in graph[node]:
            indegree[next_node] -= 1
            if indegree[next_node]==0:
                q.append(next_node)
                ans.add(next_node)
    return ans

操作2

def get_all_paths_topo(s, t, graph):
    n = len(graph)
    indegree = [0]*n
    dp = [[] for _ in range(n)]
    for i in range(n):
        for j in graph[i]:
            indegree[j] += 1
    dp[s] = [[s]]
    q = [s]
    while q:
        node = q.pop()
        for next_node in graph[node]:
            indegree[next_node] -= 1
            for path in dp[node]:
                dp[next_node].append(path+[next_node])
            if indegree[next_node]==0:
                q.append(next_node)
    return dp[t]

以上的代码只是伪代码,并不能直接运行。