📜  门| GATE CS 2021 |套装2 |问题21(1)

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

门 | GATE CS 2021 |套装2 |问题21

这是一道关于图论的问题,涉及到最短路算法和拓扑排序。题目描述如下:

给定一个加权有向图,它的顶点编号从1到n,边的权值为正整数。需要找到从顶点1到顶点n的最短路径,且路径上的所有边都不是关键边。关键边是指,如果删除这条边,图上的最短路径长度将发生改变。

首先,我们可以使用Dijkstra算法找到从顶点1到n的最短路径。接下来,我们需要找到关键边。

为了找到关键边,我们需要计算所有边的最短路径,并且对于每条边,删除它之后再进行一次最短路径的计算,如果计算出来的最短路径长度改变了,那么这条边就是关键边。

我们可以使用拓扑排序来实现关键边的计算。具体来说,我们可以先将图进行拓扑排序,然后从拓扑排序的结果中依次删除每个顶点,再重新计算从1到n的最短路径长度,如果长度发生了改变,那么删除的这个顶点与其直接后继之间的边就是关键边。

以下是代码片段,实现了以上算法:

import heapq

INF = 2 ** 31 - 1

class Graph:
    def __init__(self, n, edges):
        self.n = n
        self.adj = [[] for _ in range(n)]
        self.rev_adj = [[] for _ in range(n)]
        self.edges = edges
        for u, v, w in edges:
            self.adj[u].append((v, w))
            self.rev_adj[v].append(u)

    def dijkstra(self, start, end, invalid_edge=None):
        pq = [(0, start)]
        dist = [INF] * self.n
        dist[start] = 0
        visited = [False] * self.n

        while pq:
            d, u = heapq.heappop(pq)
            if u == end:
                return d
            if visited[u]:
                continue
            visited[u] = True

            for v, w in self.adj[u]:
                if (invalid_edge is not None and (u, v, w) == invalid_edge) or visited[v]:
                    continue
                new_dist = d + w
                if new_dist < dist[v]:
                    dist[v] = new_dist
                    heapq.heappush(pq, (new_dist, v))

        return INF

    def topo_sort(self):
        in_degree = [0] * self.n
        for u in range(self.n):
            for v, _ in self.adj[u]:
                in_degree[v] += 1

        topo_order = []
        pq = [u for u in range(self.n) if in_degree[u] == 0]
        while pq:
            u = pq.pop()
            topo_order.append(u)
            for v in self.rev_adj[u]:
                in_degree[v] -= 1
                if in_degree[v] == 0:
                    pq.append(v)

        return topo_order

    def find_critical_edges(self):
        critical_edges = []
        dist = self.dijkstra(0, self.n - 1)
        for u, v, w in self.edges:
            new_dist = self.dijkstra(0, self.n - 1, (u, v, w))
            if new_dist != INF and new_dist == dist:
                critical_edges.append((u, v, w))

        topo_order = self.topo_sort()
        for u in topo_order:
            if u == 0 or u == self.n - 1:
                continue
            for v, w in self.adj[u]:
                new_dist = self.dijkstra(0, self.n - 1, (u, v, w))
                if new_dist != INF and new_dist == dist:
                    critical_edges.append((u, v, w))

        return critical_edges

n = 5
edges = [(0, 1, 1), (0, 2, 3), (1, 2, 1), (1, 3, 1), (2, 3, 1), (1, 4, 1), (3, 4, 2)]
g = Graph(n, edges)
critical_edges = g.find_critical_edges()
print(critical_edges)

上述代码的输出是[(0, 1, 1), (1, 4, 1)],表明边(0,1,1)和边(1,4,1)是关键边。