细分图中的可到达节点 Dijkstra算法Python实现

题目大意

无向图(原始图)中有 n 个节点 \(u_i\),编号从 0 到 n - 1 。对每条边 [\(u_i,v_i\)] 增加若干节点构建“细分图”,求解从节点0出发能抵达的不超过距离为maxMove的节点数量。

输入:edges = [[0,1,10],[0,2,1],[1,2,2]], maxMoves = 6, n = 3
输出:13

解题思路

求解原始图上从节点0出发能抵达的不超过距离为maxMove的节点数量,可以直接用BFS/DFS快速解决。本题增加了“细分图”的概念,在每一条边 [\(u_i,v_i\)] 上新增 \(cnt_i\) 个节点,仍然求解新的细分图上可到达节点数量。

  • 分析数据规模,新的图节点数量可达到 10^4 * 10^4 = 10^8,无法直接对细分图建图,然后BFS/DFS。
  • 转换一下思路,可以对原始图上的边作特殊处理,即看作路径长度,那么本题可以转化为最短路问题。
  • 求解从节点0出发到其他所有节点的最短路,记录每条边两个方向走过的距离来处理额外边上的节点,统计所有总距离在最大步长范围内的点即为答案。

代码

class Solution:
    def reachableNodes(self, edges: List[List[int]], maxMoves: int, n: int) -> int:
        # 邻接矩阵
        neighbor = [[] for _ in range(n)]
        # 记录每条边的总长,[u->]方向已经访问过节点数
        new_edges = dict()

        for u, v, w in edges:
            neighbor[u].append((v, w))
            neighbor[v].append((u, w))

            new_edges[(u,v)] = [w, 0]
            new_edges[(v,u)] = [w, 0]


        from queue import PriorityQueue
        q = PriorityQueue()
        # (step, start) 优先队列,按step从小到大排序
        q.put((0, 0))
        vis = [False] * n

        ans = 0
        while not q.empty():
            step, u = q.get()

            if vis[u]:
                continue
            vis[u] = True
            ans += 1

            if step>=maxMoves:
                continue

            for v, w in neighbor[u]:
                if vis[v]:
                    # 检查边上是否有未访问的节点
                    # 剩下未走过的节点数: w-反向走过
                    left_nodes = min(w - new_edges[(v,u)][1], w-new_edges[(u,v)][1])
                    s = min(left_nodes, maxMoves-step)
                    new_edges[(u,v)][1] = s

                    ans += s
                    continue

                if step+w+1<=maxMoves:
                    ans += w
                    # print(u,v, ":", w, ans, step+w+1)
                    q.put((step+w+1, v))
                    new_edges[(u,v)][1] = w
                else:
                    # print(u,v, ":", ans, step, maxMoves-step)
                    ans += maxMoves - step
                    new_edges[(u,v)][1] = maxMoves - step
        
        return ans

后记

简简单单的想法,WA了两发才过。先是对边上节点处理不全面,需要新增走过的距离;然后是u->v的距离应为 step+w+1,put放入节点和步长位置也写反了 。


(完)

posted @ 2022-11-26 18:25  izcat  阅读(47)  评论(0编辑  收藏  举报