0% completed
Problem Statement
You are given an undirected graph with n
nodes labeled from 0
to n-1
. The graph is described using an edge
list, where each edge connects two nodes a
and b
with a probability of success of traversing that edge succProb[i]
.
Given two nodes start
and end
, find the path with the maximum probability
of success to go from start
to end
and return its success probability
.
The result should be accurate within a margin of 1e<sup>-5</sup>.
Examples
Example 1:
- Input:
- n = 5
- edges = [[0, 1], [1, 2], [2, 4], [2, 3],[3, 4], [0, 4]]
- succProb = [0.5, 0.5, 0.5, 0.5, 0.7, 0.1]
- start = 0
- end = 4
- Expected Output: 0.125
- Justification: The direct path 0 -> 4 has a probability of 0.1, while another path (e.g., 0 -> 1 -> 2 -> 4) has a higher probability of 0.125.
Example 2:
- Input:
- n = 4
- edges = [[0, 1], [1, 2], [2, 3], [0, 2]]
- succProb = [0.5, 0.6, 0.7, 0.5]
- start = 0
- end = 3
- Expected Output: 0.35
- Justification: The path 0 -> 2 -> 3 has the highest success probability (0.5 * 0.7 = 0.35).
Example 3:
- Input:
- n = 3
- edges = [[0, 1], [1, 2]]
- succProb = [0.9, 0.9]
- start = 0
- end = 2
- Expected Output: 0.81
- Justification: The only path 0 -> 1 -> 2 has a success probability of 0.9 * 0.9 = 0.81.
Constraints:
- 2 <= n <= 10<sup>4</sup>
- 0 <= start, end < n
- start != end
- 0 <= a, b < n
- a != b
- 0 <= succProb.length == edges.length <= 2*10<sup>4</sup>
- 0 <= succProb[i] <= 1
- There is at most one edge between every two nodes.
Solution
To solve this problem, we will use Dijkstra's algorithm, typically used for finding the shortest path in weighted graphs. However, instead of summing the weights, we'll multiply the probabilities to find the maximum product path.
This approach is effective because it ensures that we explore all possible paths from the starting node and select the path that yields the highest success probability. Using a priority queue, we can efficiently track the highest probability paths and update them as we explore the graph.
Step-by-Step Algorithm
-
Initialization:
- Create an adjacency list
graph
to represent the graph. Each node points to a list of edges, where each edge is a pair(neighbor, probability)
. - Initialize a max-heap (priority queue) to keep track of the nodes to explore. This heap stores pairs
(probability, node)
, sorted by probability in descending order. - Create an array
probabilities
to store the maximum probability of reaching each node from the start node. Initialize this array with zeros and set the start node's probability to 1.0.
- Create an adjacency list
-
Graph Construction:
- Iterate through each edge in the input
edges
list. - For each edge
(u, v)
with probabilityp
, add(v, p)
to the adjacency list ofu
and(u, p)
to the adjacency list ofv
.
- Iterate through each edge in the input
-
Dijkstra's Algorithm with Probability:
- Push the start node with probability 1.0 into the max-heap.
- While the max-heap is not empty:
- Pop the node with the highest probability from the heap. Let this be
current_node
withcurrent_prob
. - If
current_node
is the end node, returncurrent_prob
as the result. - For each neighbor of
current_node
:- Calculate the new probability to reach this neighbor as
current_prob * edge_prob
. - If the new probability is greater than the currently known probability to reach this neighbor, update the
probabilities
array and push the neighbor with the new probability into the max-heap.
- Calculate the new probability to reach this neighbor as
- Pop the node with the highest probability from the heap. Let this be
-
Result:
- If the heap is exhausted and the end node is not reached, return 0.0.
Algorithm Walkthrough
Input:
- n = 5
- edges = [[0, 1], [1, 2], [2, 4], [2, 3], [3, 4], [0, 4]]
- succProb = [0.5, 0.5, 0.5, 0.5, 0.7, 0.1]
- start = 0
- end = 4
Steps:
-
Initialization:
graph = {0: [], 1: [], 2: [], 3: [], 4: []}
maxHeap = []
probabilities = [1.0, 0.0, 0.0, 0.0, 0.0]
-
Graph Construction:
- Final
graph
:{ 0: [(1, 0.5), (4, 0.1)], 1: [(0, 0.5), (2, 0.5)], 2: [(1, 0.5), (4, 0.5), (3, 0.5)], 3: [(2, 0.5), (4, 0.7)], 4: [(2, 0.5), (3, 0.7), (0, 0.1)] }
- Final
-
Dijkstra's Algorithm with Probability:
- Push start node:
maxHeap.push((0, 1.0))
maxHeap = [(0, 1.0)]
- Iteration 1:
- Pop node 0 with prob 1.0:
current_node = 0
current_prob = 1.0
maxHeap = []
- Check neighbors of node 0:
- Neighbor 1 with edge prob 0.5:
- New prob = 1.0 * 0.5 = 0.5
- Update prob of node 1:
probabilities[1] = 0.5
- Push (1, 0.5) to heap:
maxHeap.push((1, 0.5))
maxHeap = [(1, 0.5)]
- Neighbor 4 with edge prob 0.1:
- New prob = 1.0 * 0.1 = 0.1
- Update prob of node 4:
probabilities[4] = 0.1
- Push (4, 0.1) to heap:
maxHeap.push((4, 0.1))
maxHeap = [(1, 0.5), (4, 0.1)]
- Neighbor 1 with edge prob 0.5:
- Pop node 0 with prob 1.0:
- Iteration 2:
- Pop node 1 with prob 0.5:
current_node = 1
current_prob = 0.5
maxHeap = [(4, 0.1)]
- Check neighbors of node 1:
- Neighbor 0 with edge prob 0.5 (new prob = 0.5 * 0.5 = 0.25, no update needed)
- Neighbor 2 with edge prob 0.5:
- New prob = 0.5 * 0.5 = 0.25
- Update prob of node 2:
probabilities[2] = 0.25
- Push (2, 0.25) to heap:
maxHeap.push((2, 0.25))
maxHeap = [(2, 0.25), (4, 0.1)]
- Pop node 1 with prob 0.5:
- Iteration 3:
- Pop node 2 with prob 0.25:
current_node = 2
current_prob = 0.25
maxHeap = [(4, 0.1)]
- Check neighbors of node 2:
- Neighbor 1 with edge prob 0.5 (new prob = 0.25 * 0.5 = 0.125, no update needed)
- Neighbor 4 with edge prob 0.5:
- New prob = 0.25 * 0.5 = 0.125
- Update prob of node 4:
probabilities[4] = 0.125
- Push (4, 0.125) to heap:
maxHeap.push((4, 0.125))
maxHeap = [(4, 0.125), (4, 0.1)]
- Neighbor 3 with edge prob 0.5:
- New prob = 0.25 * 0.5 = 0.125
- Update prob of node 3:
probabilities[3] = 0.125
- Push (3, 0.125) to heap:
maxHeap.push((3, 0.125))
maxHeap = [(4, 0.125), (4, 0.1), (3, 0.125)]
- Pop node 2 with prob 0.25:
- Iteration 4:
- Pop node 4 with prob 0.125:
current_node = 4
current_prob = 0.125
maxHeap = [(3, 0.125), (4, 0.1)]
- Node 4 is the end node, return
0.125
.
- Pop node 4 with prob 0.125:
- Push start node:
Code
Complexity Analysis
- Time Complexity: The time complexity of the algorithm is O(E + E \log V), where (E) is the number of edges and (V) is the number of vertices. This is because we use Dijkstra's algorithm with a priority queue (max-heap), which requires O(\log V) time for each update and there are (E) edges to process. Also, building the graph takes O(E) time complexity.
- Space Complexity: The space complexity is O(V + E), where (V) is the number of vertices and (E) is the number of edges. This accounts for the storage of the graph adjacency list and the priority queue.
.....
.....
.....
Table of Contents
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible