leetcode
leetcode 2501 ~ 2550
关闭分部的可行集合数目

关闭分部的可行集合数目

难度:

标签:

题目描述

There is a company with n branches across the country, some of which are connected by roads. Initially, all branches are reachable from each other by traveling some roads.

The company has realized that they are spending an excessive amount of time traveling between their branches. As a result, they have decided to close down some of these branches (possibly none). However, they want to ensure that the remaining branches have a distance of at most maxDistance from each other.

The distance between two branches is the minimum total traveled length needed to reach one branch from another.

You are given integers n, maxDistance, and a 0-indexed 2D array roads, where roads[i] = [ui, vi, wi] represents the undirected road between branches ui and vi with length wi.

Return the number of possible sets of closing branches, so that any branch has a distance of at most maxDistance from any other.

Note that, after closing a branch, the company will no longer have access to any roads connected to it.

Note that, multiple roads are allowed.

 

Example 1:

Input: n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]]
Output: 5
Explanation: The possible sets of closing branches are:
- The set [2], after closing, active branches are [0,1] and they are reachable to each other within distance 2.
- The set [0,1], after closing, the active branch is [2].
- The set [1,2], after closing, the active branch is [0].
- The set [0,2], after closing, the active branch is [1].
- The set [0,1,2], after closing, there are no active branches.
It can be proven, that there are only 5 possible sets of closing branches.

Example 2:

Input: n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]]
Output: 7
Explanation: The possible sets of closing branches are:
- The set [], after closing, active branches are [0,1,2] and they are reachable to each other within distance 4.
- The set [0], after closing, active branches are [1,2] and they are reachable to each other within distance 2.
- The set [1], after closing, active branches are [0,2] and they are reachable to each other within distance 2.
- The set [0,1], after closing, the active branch is [2].
- The set [1,2], after closing, the active branch is [0].
- The set [0,2], after closing, the active branch is [1].
- The set [0,1,2], after closing, there are no active branches.
It can be proven, that there are only 7 possible sets of closing branches.

Example 3:

Input: n = 1, maxDistance = 10, roads = []
Output: 2
Explanation: The possible sets of closing branches are:
- The set [], after closing, the active branch is [0].
- The set [0], after closing, there are no active branches.
It can be proven, that there are only 2 possible sets of closing branches.

 

Constraints:

  • 1 <= n <= 10
  • 1 <= maxDistance <= 105
  • 0 <= roads.length <= 1000
  • roads[i].length == 3
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 1 <= wi <= 1000
  • All branches are reachable from each other by traveling some roads.

代码结果

运行时间: 172 ms, 内存: 16.8 MB


// 题目思路:
// 1. 使用Floyd-Warshall算法计算每个分部之间的最短距离。
// 2. 使用Stream API遍历所有可能的关闭方案,检查剩余的分部是否都可达且最远距离不超过maxDistance。
// 3. 统计满足条件的方案数量。

import java.util.*;
import java.util.stream.*;

public class Solution {
    public int countValidCloseSchemes(int n, int maxDistance, int[][] roads) {
        int[][] dist = new int[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(dist[i], Integer.MAX_VALUE / 2);
            dist[i][i] = 0;
        }
        for (int[] road : roads) {
            int u = road[0], v = road[1], w = road[2];
            dist[u][v] = Math.min(dist[u][v], w);
            dist[v][u] = Math.min(dist[v][u], w);
        }
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
        return (int) IntStream.range(0, (1 << n)).filter(mask -> {
            List<Integer> remaining = IntStream.range(0, n).filter(i -> (mask & (1 << i)) == 0).boxed().collect(Collectors.toList());
            if (remaining.isEmpty()) return true;
            for (int i = 0; i < remaining.size(); i++) {
                for (int j = i + 1; j < remaining.size(); j++) {
                    if (dist[remaining.get(i)][remaining.get(j)] > maxDistance) {
                        return false;
                    }
                }
            }
            return true;
        }).count();
    }
}

解释

方法:

这个题解使用了深度优先搜索(DFS)和Dijkstra算法来找出所有可能的关闭分部的方案,满足剩余分部之间的最远距离不超过maxDistance。首先,构建了一个邻接表来表示所有分部之间的最短道路。然后,使用DFS枚举所有可能的关闭分部的子集。对于每个子集,使用Dijkstra算法检查从任一未关闭分部出发,是否所有未关闭分部都能在maxDistance的限制下互达。如果可以,这个子集是一个合法方案。

时间复杂度:

O(2^n * n * E log V)

空间复杂度:

O(V + E + n)

代码细节讲解

🦆
在题解中,DFS和Dijkstra算法是如何结合使用的,能否详细解释其各自在问题中扮演的角色?
在此题解中,DFS和Dijkstra算法被用于解决分部关闭问题,确保剩余分部间的最大距离不超过maxDistance。DFS(深度优先搜索)用于枚举所有可能的分部关闭子集。对每一种可能的关闭方案,DFS会遍历所有分部,决定哪些分部关闭(dt数组设为0)和哪些保持开启(dt数组设为1)。Dijkstra算法则用于验证对于每个分部关闭方案,开启的分部是否在maxDistance的限制下可以互相到达。具体地,对于每个开启的分部作为起点,使用Dijkstra算法计算其到其他所有开启分部的最短距离,并检查是否所有这些距离都不超过maxDistance。如果某一方案中所有开启的分部都是互连的,那么该方案是有效的。
🦆
题解提到使用邻接表表示所有分部之间的最短道路,为什么选择邻接表而不是邻接矩阵,特别是在处理最短路径问题时?
在处理最短路径问题时,尤其是当图中的节点数量较大或者边的数量远少于节点对的数量时,邻接表比邻接矩阵更为高效。邻接表可以更有效地管理稀疏图,因为它只存储存在的边,而不是所有可能的节点对。这降低了内存使用,并可以减少算法在无边节点间的无效操作。在使用Dijkstra算法时,使用邻接表可以直接访问到与某个节点相连的所有节点,这使得处理动态更新距离和使用优先队列(如最小堆)检查未访问节点更为高效。
🦆
在使用Dijkstra算法检查分部间互达性时,若某一分部已经关闭(dt[nxt]为0),为什么还需要继续检查从这一分部出发的路径?
在题解中,Dijkstra算法实现确实忽略了已关闭的分部(dt[nxt]为0),不会从这些分部出发计算路径。此逻辑体现在代码中,通过`if not dt[nxt]: continue`这一行实现。这确保了算法只考虑那些保持开启的分部之间的路径。如果某一分部已经关闭,则从这一分部出发的路径不会被包括在内,因为关闭的分部不应该被计入互达性的检验中。
🦆
DFS遍历所有关闭分部的子集时,如何确保不遗漏任何一种可能的关闭方案?
DFS通过递归的方式确保了每个分部都有两种可能的状态:关闭或开启。对每个分部,算法都递归地考虑了关闭它和不关闭它的情况。这种二元决策过程保证了从第一个分部到最后一个分部,所有的关闭组合都被考虑到了。具体实现中,`dfs`函数首先尝试将当前节点设为开启然后递归调用自己处理下一个分部,接着将当前节点设为关闭后再次递归调用自己。这样的递归结构保证了每一种可能的分部关闭组合都会被遍历到,从而不遗漏任何一种可能的关闭方案。

相关问题