So this question might sound dumb and obvious but for some reason, I feel like there's more to just saving the current visited node to a prev list, (like explained on Dijkstra's Wikipedia page) before marking the neighbor with the shortest tentative distance the next current node. Can someone please explain how exactly Dijkstra's algorithm reconstructs the shortest path? ty in advance
As you visit each node you are going to keep track of minimum cost of reaching the current node. For this you have to implement a min heap. "min heap" is a concrete data structure of priority queue. MinHeap is a complete binary tree in which the value in each internal node is smaller than or equal to the values in the children of that node because every insertion re-arranges the elements based on the priority value.
You will be adding a pair of (costOfSoFarVisitingNode,Node) and min heap will sort the elements based on costOfSoFarVisitingNode, so in case having this in min heap:
(2,nodeA)
(5,nodeA)
when you pop the element, min heap will be poping the (2,nodeA) so you will be always on the shortest path and keep implementing breadth first search on shortest path.
Related
I'm trying to solve a problem where I need to find the minimal cost per step to get from a start to a goal node. I think this algorithm exists, but I can not find the name of this algorithm. In the case I am working on there are only positive edges and there could be cycles.
It is not dijkstra's, because I am not looking for the total minimum cost, but for a cost that represents the minimal highest cost of all the steps.
In the following example this algorithm would thus output 3 as 3 is the highest minimal cost the algorithm can find a path for.
And is thus not the minimal cost, as that would be 4.
*The start node is gray and the goal node is green.
I think such an algorithm exists, I have tried searching on google, but so far could not find the name of this algorithm.
This can be solved with a simple modification on dijkstra.
Dijkstra works by always picking the minimum cost path. We know that as long as path costs never decrease as we move in the graph (this is true in your case), we'll always find the optimal answer by iterating in order from lowest to highest path cost. We just have to modify the cost function to be the maximum across each path and run dijkstra.
Here's a pseudocode (basically python) implementation:
import priority_queue
def min_cost_path(start, end):
min_heap = priority_queue([[0, start]]) # queue in form of (cost, node)
visited = set()
while min_heap:
# get lowest weight path thus far
# cost is the lowest cost possible to get to node
cost, node = min_heap.pop()
# optimal path to this node has already been found, ignore this
if node in visited: continue
if node == end: return cost
# this node has been visited
visited.add(node)
# add candidate node-weights to the queue
for weight, neighbor in neighbors(node):
if neighbor not in visited:
min_heap.push((max(weight, cost), neighbor))
return -1 # not possible
Well I have only heard about such problem for un-directed graphs, for directed ones (like your example) I do not know how it's called, yet its not hard to think up some efficient way to solve it:
We can just binary search for the answer, initial search space is
[0, maxWeightInWholeGraph]
During each iteration of binary search we pick some middle value m and we need to check if there exist a path from start node to goal node with edge weights <= m
This can be done by simple BFS, only traversing allowed edges
Now we divide our search space by half choosing left part if we found start-goal path and right part otherwise.
continue the binary search till we converge to answer
Complexity of this approach: O( (|V| + |E|) * log2(maxWeightInWholeGraph) )
I have questions about an optimal algorithm problem on a weighted graph. I am given an edgelist with weights, a list with savepoints, a starte- and end- node and the max distance for a step.
The output should be a list of savepoints, which are accessible in one step from starting- and end- node.
I thought of some kind of dijkstra's algorithm from each point of the list of savepoints.
I'm not sure if that's a good idea, since if I have many savepoints I calculate a lot of paths multiple times. Every idea/help is welcome!
Thank you very much in advance!
You have to have the condition that a weight cannot be negative, otherwise the problem becomes very intractable. Otherwise it's just a breadth first search, with marking the distance for every visited node. So you don't revisit a node is a previous move has visited it earlier at lower cost.
You keep a priority queue of all active nodes, so you are checking the lowest cost node each time. The priority queue is in fact the hardest part to get right. If you check the A* algorithm for my binary image library https://github.com/MalcolmMcLean/binaryimagelibrary you can take the priority queue for there. A* over a maze is very similar to shortest path over a graph, but you don't have a heuristic because you must have the exact shortest path, and instead of 4 / 8 edges per tile, you have nodes with arbitrary numbers of connections.
I can't seem to figure out how the in-order traversal of a threaded binary tree is O(N)..
Because you have to descend the links to find the the leftmost child and then go back by the thread when you want to add the parent to the traversal path. would not that be O(N^2)?
Thanks!
The traversal of a tree (threaded or not) is O(N) because visiting any node, starting from its parent, is O(1). The visitation of a node consists of three fixed operations: descending to the node from parent, the visitation proper (spending time at the node), and then returning to the parent. O(1 * N) is O(N).
The ultimate way to look at it is that the tree is a graph, and the traversal crosses each edge in the graph only twice. And the number of edges is proportional to the number of nodes since there are no cycles or redundant edges (each node can be reached by one unique path). A tree with N nodes has exactly N-1 edges: each node has an edge leading to it from its parent node, except for the root node of the tree.
At times it appears as if visiting a node requires more than one descent. For instance, after visiting the rightmost node in a subtree, we have to pop back up numerous levels before we can march to the right into the next subtree. But we did not descend all the way down just to visit that node. Each one-level descent can be accounted for as being necessary for visiting just the node immediately below, and the opposite ascent's
cost is lumped with that. By visiting a node V, we also gain access to all the nodes below it, but all those nodes benefit from and share the edge traversal from V's parent down to V, and back up again.
This is related to amortized analysis, which applies in situations where we can globally understand the overall cost based on some general observation about the structure of the problem, but at the detailed level of the individual operations, the costs are distributed in an uneven way that appears confusing.
Amortized analysis helps us understand that, for instance, N insertions into a hash table which resizes itself by growing exponentially are O(N). Most of the insertion operations are quick, but from time to time, we grow the table and process its contents. This is similar to how, from time to time during a tree traversal, we have to perform numerous consecutive ascents to climb out of a deep subtree.
The global observation about the hash table is that each item inserted into the table will move to a larger table on average about three times in three resize operations, and so each insertion can be regarded as "pre paying" for three re-insertions, which is a fixed cost. Of course, "older" items will be moved more times, but this is offset by "younger" entries that move fewer times, diluting the cost. And the global observation about the tree was already noted above: it has N-1 edges, each of which are traversed exactly twice during the traversal, so the visitation of each node "pays" for the double traversal of its respective edge. Because this is so easy to see, we don't actually have to formally apply amortized analysis to tree traversal.
Now suppose we performed an individual searches for each node (and the tree is a balanced search tree). Then the traversal would still not be O(N*N), but rather O(N log N). Suppose we have an ordered search tree which holds consecutive integers. If we increment over the integers and perform individual searches for each value, then each search is O(log N), and we end up doing N of these. In this situation, the edge traversals are no longer shared, so amortization does not apply. To reach some given node that we are searching for which is found at depth D, we have to cross D edges twice, for the sake of that node and that node alone. The next search in the loop for another integer will be completely independent of the previous one.
It may also help you to think of a linked list, which can be regarded as a very unbalanced tree. To visit all the items in a linked list of length N and return back to the head node is obviously O(N). Searching for each item individually is O(N*N), but in a traversal, we are not searching for each node individually, but using each predecessor as a springboard into finding the next node.
There is no loop to find the parent. Otherwise said, you are going through each arc between two node twice. That would be 2*number of arc = 2*(number of node -1) which is O(N).
I have been going through the algorithm of uniform-cost search and even though I am able to understand the whole priority queue procedure I am not able to understand the final stage of the algorithm.
If we look at this graph, after applying the algorithm I will have the minimum distance for each node, but suppose I want to know the path between A to G (just like the example), how will I compute that?
Usually you start with a infinite total cost for every node that hasn't been explored yet. Then you can adjust the algorithm a little bit to save the predecessor:
for each of node's neighbours n
if n is not in explored
if n is not in frontier
frontier.add(n)
set n's predecessor to node
elif n is in frontier with higher cost
replace existing node with n
set n's predecessor to node
Afterwards you can just check the sequence of predecessors, starting at your goal.
Visit for more info
https://www.youtube.com/watch?v=9vNvrRP0ymw
Insert the root into the queue
While the queue is not empty
Dequeue the maximum priority element from the queue
(If priorities are same, alphabetically smaller path is chosen)
If the path is ending in the goal state, print the path and exit
Else
Insert all the children of the dequeued element, with the cumulative costs as priority
I am looking for an algorithm to split a tree with N nodes (where the maximum degree of each node is 3) by removing one edge from it, so that the two trees that come as the result have as close as possible to N/2. How do I find the edge that is "the most centered"?
The tree comes as an input from a previous stage of the algorithm and is input as a graph - so it's not balanced nor is it clear which node is the root.
My idea is to find the longest path in the tree and then select the edge in the middle of the longest path. Does it work?
Optimally, I am looking for a solution that can ensure that neither of the trees has more than 2N / 3 nodes.
Thanks for your answers.
I don't believe that your initial algorithm works for the reason I mentioned in the comments. However, I think that you can solve this in O(n) time and space using a modified DFS.
Begin by walking the graph to count how many total nodes there are; call this n. Now, choose an arbitrary node and root the tree at it. We will now recursively explore the tree starting from the root and will compute for each subtree how many nodes are in each subtree. This can be done using a simple recursion:
If the current node is null, return 0.
Otherwise:
For each child, compute the number of nodes in the subtree rooted at that child.
Return 1 + the total number of nodes in all child subtrees
At this point, we know for each edge what split we will get by removing that edge, since if the subtree below that edge has k nodes in it, the spilt will be (k, n - k). You can thus find the best cut to make by iterating across all nodes and looking for the one that balances (k, n - k) most evenly.
Counting the nodes takes O(n) time, and running the recursion visits each node and edge at most O(1) times, so that takes O(n) time as well. Finding the best cut takes an additional O(n) time, for a net runtime of O(n). Since we need to store the subtree node counts, we need O(n) memory as well.
Hope this helps!
If you see my answer to Divide-And-Conquer Algorithm for Trees, you can see I'll find a node that partitions tree into 2 nearly equal size trees (bottom up algorithm), now you just need to choose one of the edges of this node to do what you want.
Your current approach is not working assume you have a complete binary tree, now add a path of length 3*log n to one of leafs (name it bad leaf), your longest path will be within one of a other leafs to the end of path connected to this bad leaf, and your middle edge will be within this path (in fact after you passed bad leaf) and if you partition base on this edge you have a part of O(log n) and another part of size O(n) .