100276. 最短路径中的边

2024/04/21 leetcode 共 2393 字,约 7 分钟

title

problem link

给你一个 n 个节点的无向带权图,节点编号为 0 到 n - 1 。图中总共有 m 条边,用二维数组 edges 表示,其中 edges[i] = [ai, bi, wi] 表示节点 ai 和 bi 之间有一条边权为 wi 的边。

对于节点 0 为出发点,节点 n - 1 为结束点的所有最短路,你需要返回一个长度为 m 的 boolean 数组 answer ,如果 edges[i] 至少 在其中一条最短路上,那么 answer[i] 为 true ,否则 answer[i] 为 false 。

请你返回数组 answer 。

注意,图可能不连通。

示例 1:

img

输入:n = 6, edges = [[0,1,4],[0,2,1],[1,3,2],[1,4,3],[1,5,1],[2,3,1],[3,5,3],[4,5,2]]

输出:[true,true,true,false,true,true,true,false]

解释:

以下为节点 0 出发到达节点 5 的 所有 最短路:

  • 路径 0 -> 1 -> 5 :边权和为 4 + 1 = 5 。
  • 路径 0 -> 2 -> 3 -> 5 :边权和为 1 + 1 + 3 = 5 。
  • 路径 0 -> 2 -> 3 -> 1 -> 5 :边权和为 1 + 1 + 2 + 1 = 5 。

示例 2:

img

输入:n = 4, edges = [[2,0,1],[0,1,1],[0,3,4],[3,2,2]]

输出:[true,false,false,true]

解释:

只有一条从节点 0 出发到达节点 3 的最短路 0 -> 2 -> 3 ,边权和为 1 + 2 = 3 。

提示:

  • 2 <= n <= 5 * 104
  • m == edges.length
  • 1 <= m <= min(5 * 104, n * (n - 1) / 2)
  • 0 <= ai, bi < n
  • ai != bi
  • 1 <= wi <= 105
  • 图中没有重边。

solution

dijkstra 求最短路径上的边。也可以使用0和n-1这两个点分别dijkstra,之后对于点u,v这个u - v的边,判断u到0以及v到n-1距离就可以得出它是不是最短路径上的边。

from collections import defaultdict, Counter

MOD = int(1e9 + 7)
INF = float('inf')
import sortedcontainers
import bisect
import heapq
class Graph:

    def __init__(self):
        self.path = collections.defaultdict(lambda: -1)
        self.path_pre = collections.defaultdict(list)

    '''
    边数组转邻接表
    '''
    def dijkstra(self, graph, start):
        '''
        重要的是定义成本,可能是路径,可能是花费, 如果有限制次数,也可以将次数也算进成本里
        如果是次数
        graph = collections.defaultdict(list)
        for u,v,w in edges:
            graph[u].append((v,w))
            graph[v].append((u,w))
        :param graph:  存了每个点的next node
        '''
        import heapq
        heap = [(0, start, -1)]  # cost from start node,end node
        dist = {}
        # self.path = [-1 for _ in range(len(graph.keys()))]
        while heap:
            (cost, u, pre) = heapq.heappop(heap)
            if u in dist:
                if cost == dist[u]:
                    self.path_pre[u].append(pre)
                continue
            dist[u] = cost
            self.path_pre[u].append(pre)
            self.path[u] = pre
            for v, c in graph[u]:
                if v in dist:
                    continue
                next = cost + c
                heapq.heappush(heap, (next, v, u))
        return dist

    def get_dijkstra_path_for_multiple(self, j):
        '''
        返回一个树形结构,j这个终点到起点的所有的点位以及对应的上一个点位的list
        eg: defaultdict(<class 'list'>, {5: [1, 3], 1: [0, 3], 0: [-1], 3: [2], 2: [0]})
        '''
        nxt = collections.defaultdict(list)
        def add_to_nxt(i):
            if i not in self.path_pre:
                return []
            nxt[i] = self.path_pre[i]
            for v in self.path_pre[i]:
                add_to_nxt(v)
        add_to_nxt(j)
        return nxt

class Solution:
    def findAnswer(self, n: int, edges: List[List[int]]) -> List[bool]:
        graph = collections.defaultdict(list)
        for u, v, w in edges:
            graph[u].append((v, w))
            graph[v].append((u, w))
        G = Graph()
        d = G.dijkstra(graph, 0)
        # print(d)
        pre = G.get_dijkstra_path_for_multiple(n - 1)
        # print(pre)
        for k in pre.keys():
            pre[k] = set(pre[k])
        # print(pre)
        ans = []
        for i,(u,v,_) in enumerate(edges):
            # print(i,u,v)
            if u in pre and v in pre[u] or v in pre and u in pre[v]:
                ans.append(True)
            else:
                ans.append(False)
        return ans

Search

    Table of Contents