力扣 2039. 网络空闲的时刻

179 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目来源:leetcode-cn.com/problems/th…

大致题意: 给 n 个节点(编号0 ~ n-1)表示路由器节点,一个二维数组表示相连的节点,一个数组表示每个节点的耐心时间 用 0 节点表示服务器,从 0 秒开始,所有路由器向服务器发送消息,每秒消息只能移动到相邻节点,服务器收到消息后原路返回给节点。每秒开始时,路由器都检查是否收到回复,若没有且当前时间超过了耐心时间,那么重新发送消息;若收到了则不再发送消息 假设消息发送都经过最优路径,求最短在第几秒时,整个网络没有消息

思路

遍历求出每个路由器的消息在网络上的时间,取最长的那个时间 + 1 即为所求秒数

因为需要发送时间尽可能地短,所以消息都经过最短路径发送,这也就是一个边权值相同的最短路径问题,于是可以用 BFS

BFS

  1. 求出每个节点相连的边
  2. 以 0 为源点,开始 BFS
  3. 对于搜索的每个节点,求出其消息在网络中滞留的时间,并统计最大值
  4. 最大值 + 1 即为网络上没有消息的时间

节点消息在网络上滞留的时间为:

  • 节点与源点的最短路径长度 * 2 + 节点最后一次发送消息的时间

使用 time 表示节点与源点的最短路径长度 * 2,使用 p 表示该节点对应的耐心时间,则有:

  • 若 time % p = 0,那么可以先求出重发次数:time / p,因为每秒开始时先检查是否有回复,所以在 time 秒时没有发送消息,那么最后一次发送消息的时间为 (time / p - 1) * p
  • 否则,其为 重发次数 * p,即 time / p * p

    public int networkBecomesIdle(int[][] edges, int[] patience) {
        Set<Integer> vis = new HashSet<>(); // 标记访问过的节点
        Map<Integer, List<Integer>> map = new HashMap<>();  // 存每个节点相连的节点
        Queue<int[]> queue = new ArrayDeque<>();    // BFS 的队列
        int n = patience.length;
        // 遍历获取所有节点的相邻节点
        for (int[] edge : edges) {
            int x = edge[0];
            int y = edge[1];
            List<Integer> xList = map.getOrDefault(x, new ArrayList<>());
            xList.add(y);
            map.put(x, xList);
            List<Integer> yList = map.getOrDefault(y, new ArrayList<>());
            yList.add(x);
            map.put(y, yList);
        }
        // 源点入队
        // 两个值,第一个表示节点编号,第二个表示其与源点的最短距离
        queue.offer(new int[]{0, 0});
        vis.add(0);
        int ans = Integer.MIN_VALUE;
        while (!queue.isEmpty()) {
            // 出队
            int[] cur = queue.poll();
            // 获取节点
            int x = cur[0];
            if (x != 0) {
                // 获取最短的来回时间
                int curTime = cur[1] * 2;
                // 求其消息在网络上的滞留时间
                if (curTime % patience[x] == 0) {
                    curTime += (curTime / patience[x] - 1) * patience[x];
                } else {
                    curTime += (curTime / patience[x]) * patience[x];
                }
                // 更新最大值
                ans = Math.max(ans, curTime);
            }
            List<Integer> list = map.get(x);
            // 将相邻未访问的点入队列
            for (int to : list) {
                if (!vis.contains(to)) {
                    vis.add(to);
                    queue.offer(new int[]{to, cur[1] + 1});
                }
            }
        }
        return ans + 1;
    }