给你一个无向图(原始图),图中有
n
个节点,编号从0
到n - 1
。你决定将图中的每条边 细分 为一条节点链,每条边之间的新节点数各不相同。图用由边组成的二维数组
edges
表示,其中edges[i] = [ui, vi, cnti]
表示原始图中节点ui
和vi
之间存在一条边,cnti
是将边 细分 后的新节点总数。注意,cnti == 0
表示边不可细分。要 细分 边
[ui, vi]
,需要将其替换为(cnti + 1)
条新边,和cnti
个新节点。新节点为x1
,x2
, …,xcnti
,新边为[ui, x1]
,[x1, x2]
,[x2, x3]
, …,[xcnti+1, xcnti]
,[xcnti, vi]
。现在得到一个 新的细分图 ,请你计算从节点
0
出发,可以到达多少个节点?如果节点间距离是maxMoves
或更少,则视为 可以到达 。给你原始图和
maxMoves
,返回 新的细分图中从节点0
出发 *可到达的节点数* 。
You are given an undirected graph (the “original graph”) with
n
nodes labeled from0
ton - 1
. You decide to subdivide each edge in the graph into a chain of nodes, with the number of new nodes varying between each edge.The graph is given as a 2D array of
edges
whereedges[i] = [ui, vi, cnti]
indicates that there is an edge between nodesui
andvi
in the original graph, andcnti
is the total number of new nodes that you will subdivide the edge into. Note thatcnti == 0
means you will not subdivide the edge.To subdivide the edge
[ui, vi]
, replace it with(cnti + 1)
new edges andcnti
new nodes. The new nodes arex1
,x2
, …,xcnti
, and the new edges are[ui, x1]
,[x1, x2]
,[x2, x3]
, …,[xcnti-1, xcnti]
,[xcnti, vi]
.In this new graph, you want to know how many nodes are reachable from the node
0
, where a node is reachable if the distance ismaxMoves
or less.Given the original graph and
maxMoves
, return the number of nodes that are reachable from node0
in the new graph.
今天的官题写的还不错
[全市静默的第二天 感觉再关几天就学不动了 ]
思路
首先考虑简单情况:当图中只存在原始节点而不存在细分节点时,此题可以用 Dijkstra 算法解决:将输入的 edgess 转换成邻接表 adList,维护一个小顶堆 pq 可以依次计算出图中的起点到各个点最短路径,从而计算出可到达节点。
再考虑当每条边上都加入细分节点后,需要考虑细分节点是否可达。
实现
class Solution {
public int reachableNodes(int[][] edges, int maxMoves, int n) {
// 初始化邻接表
List<int[]>[] adList = new List[n];
for (int i = 0; i < n; i++) {
adList[i] = new ArrayList<int[]>();
}
for (int[] edge : edges) {
int u = edge[0], v = edge[1], nodes = edge[2];
adList[u].add(new int[]{v, nodes});
adList[v].add(new int[]{u, nodes});
}
Map<Integer, Integer> used = new HashMap<Integer, Integer>();// 细分情况下、新节点编号能够到达的新结点数【可能为负数】
Set<Integer> visited = new HashSet<Integer>();
int reachableNodes = 0;
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[0] - b[0]);// 存储起点至节点的最短路径 a[0]为路径 从小到大存储
pq.offer(new int[]{0, 0});
while (!pq.isEmpty() && pq.peek()[0] <= maxMoves) {
int[] pair = pq.poll();
int step = pair[0], u = pair[1];// u为当前节点 step为节点0至u的最短距离
if (!visited.add(u)) {// 如果u已经被访问过 那么跳过该节点 避免重复计算
continue;
}
reachableNodes++;// 记录能够到达的原节点数量
for (int[] next : adList[u]) {// 存入下一个可以访问的节点
int v = next[0], nodes = next[1];
if (nodes + step + 1 <= maxMoves && !visited.contains(v)) {
pq.offer(new int[]{nodes + step + 1, v});// 能够访问 入队
}
used.put(encode(u, v, n), Math.min(nodes, maxMoves - step));
}
}
// 计算能够到达的新节点的数量
for (int[] edge : edges) {
int u = edge[0], v = edge[1], nodes = edge[2];
reachableNodes += Math.min(nodes, used.getOrDefault(encode(u, v, n), 0) + used.getOrDefault(encode(v, u, n), 0));
}
return reachableNodes;
}
// 生成细分图中的节点编号
public int encode(int u, int v, int n) {
return u * n + v;
}
}
复杂度
作者:力扣官方题解
链接:https://leetcode.cn/problems/reachable-nodes-in-subdivided-graph/solutions/1990614/xi-fen-tu-zhong-de-ke-dao-da-jie-dian-by-u8m1/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。