Reachable Nodes In Subdivided Graph

Starting with an undirected graph (the "original graph") with nodes from 0 to N-1, subdivisions are made to some of the edges.

The graph is given as follows: edges[k] is a list of integer pairs (i, j, n) such that (i, j) is an edge of the original graph,

and n is the total number of new nodes on that edge. 

Then, the edge (i, j) is deleted from the original graph, n new nodes (x_1, x_2, ..., x_n) are added to the original graph,

and n+1 new edges (i, x_1), (x_1, x_2), (x_2, x_3), ..., (x_{n-1}, x_n), (x_n, j) are added to the original graph.

Now, you start at node 0 from the original graph, and in each move, you travel along one edge. 

Return how many nodes you can reach in at most M moves.

 

Example 1:

Input: edges = [[0,1,10],[0,2,1],[1,2,2]], M = 6, N = 3
Output: 13
Explanation: 
The nodes that are reachable in the final graph after M = 6 moves are indicated below.

Example 2:

Input: edges = [[0,1,4],[1,2,6],[0,2,8],[1,3,1]], M = 10, N = 4
Output: 23

 

Note:

  1. 0 <= edges.length <= 10000
  2. 0 <= edges[i][0] < edges[i][1] < N
  3. There does not exist any i != j for which edges[i][0] == edges[j][0] and edges[i][1] == edges[j][1].
  4. The original graph has no parallel edges.
  5. 0 <= edges[i][2] <= 10000
  6. 0 <= M <= 10^9
  7. 1 <= N <= 3000
  8. A reachable node is a node that can be travelled to using at most M moves starting from node 0.

题目理解:

给定一个无向图,从0节点开始可以走M步,问最多能访问多少个节点。注意这个图的一部分边被划分了,也就是向边中添加了若干个子节点。

解题思路:

找到每一个原始节点能够走的最长步数,然后按照这个最大步数访问它周围的子节点。为了避免重复,所有访问过的节点的数目都从子节点数目中减掉。最后加上所有能够访问的原始节点数目。

找到每一个原始节点能够走的最大步数可以使用广度优先搜索BFS,这里的搜索条件是某一个原始节点的最大步数有变化。

为了降低复杂度,使用一个字典存储每一个原始节点直接连通的节点。

代码如下:

class Solution {
    public int reachableNodes(int[][] edges, int M, int N) {
        Queue<Integer> qu = new LinkedList<Integer>();
        Set<Integer> visited = new HashSet<Integer>();
        Map<Integer, Set<Integer>> map = new HashMap<Integer, Set<Integer>>();
        int res = 0;
        int[][] graph = new int[N][N];
        int[] max = new int[N];
        qu.offer(0);
        max[0] = M;
        for(int[] it : graph) {
        	Arrays.fill(it, -1);
        }
        for(int[] it : edges) {
        	graph[it[0]][it[1]] = it[2];
        	graph[it[1]][it[0]] = it[2];
        	if(!map.containsKey(it[0]))
        		map.put(it[0], new HashSet<Integer>());
        	if(!map.containsKey(it[1]))
        		map.put(it[1], new HashSet<Integer>());
        	map.get(it[0]).add(it[1]);
        	map.get(it[1]).add(it[0]);
        }
        while(!qu.isEmpty()) {
        	int start = qu.poll();
        	for(int end : map.getOrDefault(start, new HashSet<Integer>())) {
        		if(graph[start][end] == -1 || start == end)
    				continue;
    			int remain = max[start] - Math.min(max[start], graph[start][end] + 1);
    			if(remain > max[end]) {//continue to visit other nodes
    				qu.offer(end);
    				max[end] = remain;
    			}
        	}
        }
        for(int i = 0; i < N; i++) {
        	int dis = max[i];
        	if(dis > 0) {
        		visited.add(i);
        		for(int j : map.getOrDefault(i, new HashSet<Integer>())) {
        			if(graph[i][j] < 0)
        				continue;
        			if(dis > graph[i][j])
        				visited.add(j);
        			res += Math.min(dis, graph[i][j]);
        			int temp = Math.max(0, graph[i][j] - dis);
        			graph[i][j] = temp;
        			graph[j][i] = temp;
        		}
        	}
        }
        return res + visited.size();
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值