Related
Given a graph G, a vertex u, and an array VAL[] that associates every vertex v with a natural number(For each vertex v of V, VAL[v]=n, where n is a natural number).
A simple path in G is maximal if it can't be expanded anymore, maintaining the property to be simple.
Define an algorithm that verifies that all simple maximal paths, that depart from vertex u necessarily pass 2 vertices associated with numbers of different parity.
Is there an algorithm that can solve it in linear time on the dimensions of the graph?
Italian translation in this image:
edited:
my first solution.
class color(Enum):
white = "white"
grey = "grey"
black = "black"
class Node(object):
def __init__(self, name, adjacency=[],
visited=False, predecessor=None):
self.name = name
self.adjacency = adjacency
self.visited = visited
self.predecessor = predecessor
def __repr__(self) -> str:
return f'''{self.name}'''
def append(self, vertex):
self.adjacency.append(vertex)
def dfs(start: Node, VAL: dict):
start.visited == color.grey
parity = VAL[start.name] % 2
for v in start.adjacenciesList:
if v.visited == color.white:
if parity != (VAL[v.name] % 2):
return True
if dfs(v):
return True
start.visited == color.black
return False
if __name__ == "__main__":
node1 = Node("A")
node2 = Node("B")
node3 = Node("C")
node4 = Node("D")
node1.append(node2)
node1.append(node3)
node2.append(node3)
node2.append(node4)
node3.append(node4)
VAL = {"A": 1, "B": 3, "C": 4, "D": 5}
print(dfs(node1, VAL))
Run a BFS and for each node in the queue maintain the following state:
Can be reached visiting only odd parity on the way
Can be reached visiting only even parity on the way
For every terminal node -- a node that has no neighbours that have not already been visited -- answer that question also considering its visited neighbours (even as we don't continue the BFS from it). A terminal node that at the end of the BFS answers yes to any of the state questions would invalidate the graph. It can answer yes if it has only one visited neighbour (the one we came from), or any combination of two.
Say we have the graph,
[(1, 2), (1, 3), (1, 5), (2, 5), (3, 5)]
1 - 2
| \ |
3 - 5
u = 1
(for simplicity, each node's VAL is the same as its label). BFS elements represent (node, can_be_reached_even, can_be_reached_odd). Something like:
queue: [(1, False, True)]
visited: {
1: [False, True]
}
queue: [(2, False, False), (3, False, True), (5, False, True)]
visited: {
1: [False, True],
2: [False, False],
3: [False, True],
5: [False, True]
}
When we reach 2, all its neighbours are visited so we consider that they are both odd and 2 is even and there's no way to keep one parity state by placing 2 in a path.
When we reach 3, all its neighbours have been visited so there's some path from u to them. We see that we can connect two of the neighbours (which are also all of them), 1 and 5, via 3, having reached them with odd parity. Since 3 is also odd, this would make an odd simple path, which would invalidate the graph and we can exit early.
The above describes the basic idea. It would need some work to check if it is sound and complete as is or may need some tweaking (or overhauling or discarding) for more complex scenarios.
I have a tree as input to the breadth first search and I want to know as the algorithm progresses at which level it is?
# Breadth First Search Implementation
graph = {
'A':['B','C','D'],
'B':['A'],
'C':['A','E','F'],
'D':['A','G','H'],
'E':['C'],
'F':['C'],
'G':['D'],
'H':['D']
}
def breadth_first_search(graph,source):
"""
This function is the Implementation of the breadth_first_search program
"""
# Mark each node as not visited
mark = {}
for item in graph.keys():
mark[item] = 0
queue, output = [],[]
# Initialize an empty queue with the source node and mark it as explored
queue.append(source)
mark[source] = 1
output.append(source)
# while queue is not empty
while queue:
# remove the first element of the queue and call it vertex
vertex = queue[0]
queue.pop(0)
# for each edge from the vertex do the following
for vrtx in graph[vertex]:
# If the vertex is unexplored
if mark[vrtx] == 0:
queue.append(vrtx) # mark it as explored
mark[vrtx] = 1 # and append it to the queue
output.append(vrtx) # fill the output vector
return output
print breadth_first_search(graph, 'A')
It takes tree as an input graph, what I want is, that at each iteration it should print out the current level which is being processed.
Actually, we don't need an extra queue to store the info on the current depth, nor do we need to add null to tell whether it's the end of current level. We just need to know how many nodes the current level contains, then we can deal with all the nodes in the same level, and increase the level by 1 after we are done processing all the nodes on the current level.
int level = 0;
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int level_size = queue.size();
while (level_size-- != 0) {
Node temp = queue.poll();
if (temp.right != null) queue.add(temp.right);
if (temp.left != null) queue.add(temp.left);
}
level++;
}
You don't need to use extra queue or do any complicated calculation to achieve what you want to do. This idea is very simple.
This does not use any extra space other than queue used for BFS.
The idea I am going to use is to add null at the end of each level. So the number of nulls you encountered +1 is the depth you are at. (of course after termination it is just level).
int level = 0;
Queue <Node> queue = new LinkedList<>();
queue.add(root);
queue.add(null);
while(!queue.isEmpty()){
Node temp = queue.poll();
if(temp == null){
level++;
queue.add(null);
if(queue.peek() == null) break;// You are encountering two consecutive `nulls` means, you visited all the nodes.
else continue;
}
if(temp.right != null)
queue.add(temp.right);
if(temp.left != null)
queue.add(temp.left);
}
Maintain a queue storing the depth of the corresponding node in BFS queue. Sample code for your information:
queue bfsQueue, depthQueue;
bfsQueue.push(firstNode);
depthQueue.push(0);
while (!bfsQueue.empty()) {
f = bfsQueue.front();
depth = depthQueue.front();
bfsQueue.pop(), depthQueue.pop();
for (every node adjacent to f) {
bfsQueue.push(node), depthQueue.push(depth+1);
}
}
This method is simple and naive, for O(1) extra space you may need the answer post by #stolen_leaves.
Try having a look at this post. It keeps track of the depth using the variable currentDepth
https://stackoverflow.com/a/16923440/3114945
For your implementation, keep track of the left most node and a variable for the depth. Whenever the left most node is popped from the queue, you know you hit a new level and you increment the depth.
So, your root is the leftMostNode at level 0. Then the left most child is the leftMostNode. As soon as you hit it, it becomes level 1. The left most child of this node is the next leftMostNode and so on.
With this Python code you can maintain the depth of each node from the root by increasing the depth only after you encounter a node of new depth in the queue.
queue = deque()
marked = set()
marked.add(root)
queue.append((root,0))
depth = 0
while queue:
r,d = queue.popleft()
if d > depth: # increase depth only when you encounter the first node in the next depth
depth += 1
for node in edges[r]:
if node not in marked:
marked.add(node)
queue.append((node,depth+1))
If your tree is perfectly ballanced (i.e. each node has the same number of children) there's actually a simple, elegant solution here with O(1) time complexity and O(1) space complexity. The main usecase where I find this helpful is in traversing a binary tree, though it's trivially adaptable to other tree sizes.
The key thing to realize here is that each level of a binary tree contains exactly double the quantity of nodes compared to the previous level. This allows us to calculate the total number of nodes in any tree given the tree's depth. For instance, consider the following tree:
This tree has a depth of 3 and 7 total nodes. We don't need to count the number of nodes to figure this out though. We can compute this in O(1) time with the formaula: 2^d - 1 = N, where d is the depth and N is the total number of nodes. (In a ternary tree this is 3^d - 1 = N, and in a tree where each node has K children this is K^d - 1 = N). So in this case, 2^3 - 1 = 7.
To keep track of depth while conducting a breadth first search, we simply need to reverse this calculation. Whereas the above formula allows us to solve for N given d, we actually want to solve for d given N. For instance, say we're evaluating the 5th node. To figure out what depth the 5th node is on, we take the following equation: 2^d - 1 = 5, and then simply solve for d, which is basic algebra:
If d turns out to be anything other than a whole number, just round up (the last node in a row is always a whole number). With that all in mind, I propose the following algorithm to identify the depth of any given node in a binary tree during breadth first traversal:
Let the variable visited equal 0.
Each time a node is visited, increment visited by 1.
Each time visited is incremented, calculate the node's depth as depth = round_up(log2(visited + 1))
You can also use a hash table to map each node to its depth level, though this does increase the space complexity to O(n). Here's a PHP implementation of this algorithm:
<?php
$tree = [
['A', [1,2]],
['B', [3,4]],
['C', [5,6]],
['D', [7,8]],
['E', [9,10]],
['F', [11,12]],
['G', [13,14]],
['H', []],
['I', []],
['J', []],
['K', []],
['L', []],
['M', []],
['N', []],
['O', []],
];
function bfs($tree) {
$queue = new SplQueue();
$queue->enqueue($tree[0]);
$visited = 0;
$depth = 0;
$result = [];
while ($queue->count()) {
$visited++;
$node = $queue->dequeue();
$depth = ceil(log($visited+1, 2));
$result[$depth][] = $node[0];
if (!empty($node[1])) {
foreach ($node[1] as $child) {
$queue->enqueue($tree[$child]);
}
}
}
print_r($result);
}
bfs($tree);
Which prints:
Array
(
[1] => Array
(
[0] => A
)
[2] => Array
(
[0] => B
[1] => C
)
[3] => Array
(
[0] => D
[1] => E
[2] => F
[3] => G
)
[4] => Array
(
[0] => H
[1] => I
[2] => J
[3] => K
[4] => L
[5] => M
[6] => N
[7] => O
)
)
Set a variable cnt and initialize it to the size of the queue cnt=queue.size(), Now decrement cnt each time you do a pop. When cnt gets to 0, increase the depth of your BFS and then set cnt=queue.size() again.
In Java it would be something like this.
The idea is to look at the parent to decide the depth.
//Maintain depth for every node based on its parent's depth
Map<Character,Integer> depthMap=new HashMap<>();
queue.add('A');
depthMap.add('A',0); //this is where you start your search
while(!queue.isEmpty())
{
Character parent=queue.remove();
List<Character> children=adjList.get(parent);
for(Character child :children)
{
if (child.isVisited() == false) {
child.visit(parent);
depthMap.add(child,depthMap.get(parent)+1);//parent's depth + 1
}
}
}
Use a dictionary to keep track of the level (distance from start) of each node when exploring the graph.
Example in Python:
from collections import deque
def bfs(graph, start):
queue = deque([start])
levels = {start: 0}
while queue:
vertex = queue.popleft()
for neighbour in graph[vertex]:
if neighbour in levels:
continue
queue.append(neighbour)
levels[neighbour] = levels[vertex] + 1
return levels
I write a simple and easy to read code in python.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def dfs(self, root):
assert root is not None
queue = [root]
level = 0
while queue:
print(level, [n.val for n in queue if n is not None])
mark = len(queue)
for i in range(mark):
n = queue[i]
if n.left is not None:
queue.append(n.left)
if n.right is not None:
queue.append(n.right)
queue = queue[mark:]
level += 1
Usage,
# [3,9,20,null,null,15,7]
n3 = TreeNode(3)
n9 = TreeNode(9)
n20 = TreeNode(20)
n15 = TreeNode(15)
n7 = TreeNode(7)
n3.left = n9
n3.right = n20
n20.left = n15
n20.right = n7
DFS().dfs(n3)
Result
0 [3]
1 [9, 20]
2 [15, 7]
I don't see this method posted so far, so here's a simple one:
You can "attach" the level to the node. For e.g., in case of a tree, instead of the typical queue<TreeNode*>, use a queue<pair<TreeNode*,int>> and then push the pairs of {node,level}s into it. The root would be pushed in as, q.push({root,0}), its children as q.push({root->left,1}), q.push({root->right,1}) and so on...
We don't need to modify the input, append nulls or even (asymptotically speaking) use any extra space just to track the levels.
Let us say the space = [0, 100] and there are a number of intervals given.
These intervals are fragments of the space, and possibly overlap.
[0, 30], [0, 20], [10, 40], [30, 50], [50, 90], [70, 100]
is a set of intervals.
An example of a set of intervals that span the entire space chosen from the above set is:
[0, 30], [10, 40], [30, 50], [50, 90], [70, 100]
Another example is
[0, 30], [30, 50], [50, 90], [70, 100]
which is the set in the previous example without [10, 40].
I want to find all combinations of such sets of intervals to calculate cost for each interval and find the one with the lowest cost.
from operator import itemgetter
import collections
tmp = [(0, 30), (0, 20), (10, 40), (30, 50), (50, 90), (70, 100), ]
aa = sorted(tmp, key=itemgetter(1)) # sort with respect to 1st elem
a = set(aa)
space = 100
d_conn = 15
RTT = d_conn*2
bandwidth = 10
def get_marginal_cost(fragment):
return RTT + (fragment[1] - fragment[0])/bandwidth
def dfs(a, start, path=None):
if path is None:
path = [start, ]
if start[1] == space:
yield path
for frgmt in a - set(path):
l = frgmt[0]
r = frgmt[1]
if start[0] < l <= start[1] <= r:
# if l <= start[1] <= r:
yield dfs(a, frgmt, path + [frgmt, ])
for z in a:
if z[0] == 0:
for output in list(dfs(a, z)):
for outpu in list(output):
for outp in list(outpu):
for out in list(outp):
for ou in list(out):
print list(ou)
This is my attempt so far, but I could not finish.
Particularly, I am looking to finish this without use of yield functionality in Python, because I am not familiar with it and I probably want to implement this in C++.
Can anyone help me write a working program that solves this problem?
Thank you.
Is it really necessary to build a tree just to find the minimum cost?
Probably not (assuming that your currently unspecified cost function displays optimal substructure).
For a linear cost function, the following classic algorithm runs in time O(n log n), where n is the number of intervals. Initialize a sorted map from mid to the cost of covering [0, mid]. Initially, this map has one entry, 0 -> 0. Sort the intervals by right endpoint and process them in order as follows. To process [a, b], find the map entry mid -> cost such that mid >= a is as small as possible. (If no such entry exists, then just continue.) Let cost' = cost + Cost([a, b]), where Cost([a, b]) is unspecified but always positive. While the last entry in the map has cost greater than or equal to cost', delete it. Insert b -> cost'. To finish, look up the successor of end, where [0, end] is the space to be covered.
Even if your cost function is not linear, since it's a (presumably monotone) function of the total interval length and the number of intervals, we can get an O(n^2)-time algorithm that, instead of remembering just one cost for each midpoint, remembers for each integer between 0 and n the cost for a solution that uses the specified number of intervals.
You don't have to explicitly build the tree - you could use a recursive depth first search to achieve the same effect.
At each point in the recursive depth first search you will have built a set of intervals covering [0,x] and you will want to extend this. To do this you need to find all of the intervals which intersect with x and end after x. As you recurse down the tree you will want to do the same search for y > x and so on.
One way to speed this up would be to put the start and end points of the intervals into an array and sort them. You keep a pointer into the array which marks the position x and a set of intervals that cover x, perhaps stored as a hash set. When you advance the position x you move the pointer along the list, deleting intervals from the set when you see their right hand points, and adding intervals to the set when you see their left hand points. You can back up in a very similar way.
This should allow you to keep track of what intervals you can use to extend the covering [0,x] at each point without searching through every possible interval.
This should allow you to enumerate the list of all possible coverings reasonably efficiently. To find the cheapest covering without enumerating all possible coverings we would need to know more about the cost function than you have put in the question.
I am pretty sure this can be optimised, but below is a working version. Will try to optimize it and update again:
from operator import itemgetter
import collections
import random
def generate_sample_input(space):
# This method generates a set of tuples, each tuple consisting of 2 nos
low, high = space
init = (low, random.randint(low + 1, (low + high)/2))
last = (random.randint((low + high)/2 + 1, high), high)
mid = random.randint(init[1] + 1, last[0] - 1)
ranges = [init, (init[1] - 1, mid + 1), (mid - 1, last[0] + 1), last]
nums = {i for tup in ranges for i in tup}
for _ in range(random.randint(0, 20)):
low = random.randint(space[0], space[1] - 1)
high = random.randint(low, space[1])
if all(i not in nums for i in (low, high)):
nums |= {low, high}
ranges.append((low, high))
return sorted(set(ranges), key = lambda x: x[0])
class Node(object):
def __init__(self, tup):
assert len(tup) == 2 and all(type(x) == int for x in tup)
self.low, self.high = tup
self.visitable_nodes = []
self.piggybacker_nodes = []
def __repr__(self):
return "(%s, %s)" % (self.low, self.high)
def set_visitable(self, node):
assert type(node) == Node
if self.low < node.low and node.high < self.high:
self.piggybacker_nodes.append(node)
elif self.low < node.low < self.high:
self.visitable_nodes.append(node)
class Graph(object):
def __init__(self):
self.sources, self.sinks, self.nodes = [], [], []
def add(self, node, is_sink=False, is_source=False):
assert type(node) == Node and not (is_sink and is_source)
for old_node in self.nodes:
old_node.set_visitable(node)
node.set_visitable(old_node)
self.nodes.append(node)
if is_sink:
self.sinks.append(node)
elif is_source:
self.sources.append(node)
def create_graph(self, ranges=[], space=[]):
for tup in ranges:
self.add(Node(tup), is_source=tup[0]==space[0],
is_sink=tup[1]==space[1])
def dfs(stack=[], nodes=[], sinks=[], level=0):
for node in nodes:
if node in sinks:
print stack + [node]
dfs(stack + [node], node.visitable_nodes, sinks, level + 1)
def main():
space = (0, 100)
ranges = generate_sample_input(space)
graph = Graph()
graph.create_graph(space=space, ranges=ranges)
print ranges
dfs([], nodes=graph.sources, sinks=graph.sinks)
if __name__ == "__main__":
main()
I have spent lots of time on this issue. However, I can only find solutions with non-recursive methods for a tree: Non recursive for tree, or a recursive method for the graph, Recursive for graph.
And lots of tutorials (I don't provide those links here) don't provide the approaches as well. Or the tutorial is totally incorrect. Please help me.
Updated:
It's really hard to describe:
If I have an undirected graph:
1
/ | \
4 | 2
3 /
1-- 2-- 3 --1 is a cycle.
At the step: 'push the neighbors of the popped vertex into the stack', what's the order in which the vertices should be pushed?
If the pushed order is 2, 4, 3, the vertices in the stack are:
| |
|3|
|4|
|2|
_
After popping the nodes, we get the result: 1 -> 3 -> 4 -> 2 instead of 1--> 3 --> 2 -->4.
It's incorrect. What condition should I add to stop this scenario?
A DFS without recursion is basically the same as BFS - but use a stack instead of a queue as the data structure.
The thread Iterative DFS vs Recursive DFS and different elements order handles with both approaches and the difference between them (and there is! you will not traverse the nodes in the same order!)
The algorithm for the iterative approach is basically:
DFS(source):
s <- new stack
visited <- {} // empty set
s.push(source)
while (s is not empty):
current <- s.pop()
if (current is in visited):
continue
visited.add(current)
// do something with current
for each node v such that (current,v) is an edge:
s.push(v)
This is not an answer, but an extended comment, showing the application of the algorithm in #amit's answer to the graph in the current version of the question, assuming 1 is the start node and its neighbors are pushed in the order 2, 4, 3:
1
/ | \
4 | 2
3 /
Actions Stack Visited
======= ===== =======
push 1 [1] {}
pop and visit 1 [] {1}
push 2, 4, 3 [2, 4, 3] {1}
pop and visit 3 [2, 4] {1, 3}
push 1, 2 [2, 4, 1, 2] {1, 3}
pop and visit 2 [2, 4, 1] {1, 3, 2}
push 1, 3 [2, 4, 1, 1, 3] {1, 3, 2}
pop 3 (visited) [2, 4, 1, 1] {1, 3, 2}
pop 1 (visited) [2, 4, 1] {1, 3, 2}
pop 1 (visited) [2, 4] {1, 3, 2}
pop and visit 4 [2] {1, 3, 2, 4}
push 1 [2, 1] {1, 3, 2, 4}
pop 1 (visited) [2] {1, 3, 2, 4}
pop 2 (visited) [] {1, 3, 2, 4}
Thus applying the algorithm pushing 1's neighbors in the order 2, 4, 3 results in visit order 1, 3, 2, 4. Regardless of the push order for 1's neighbors, 2 and 3 will be adjacent in the visit order because whichever is visited first will push the other, which is not yet visited, as well as 1 which has been visited.
The DFS logic should be:
1) if the current node is not visited, visit the node and mark it as visited
2) for all its neighbors that haven't been visited, push them to the stack
For example, let's define a GraphNode class in Java:
class GraphNode {
int index;
ArrayList<GraphNode> neighbors;
}
and here is the DFS without recursion:
void dfs(GraphNode node) {
// sanity check
if (node == null) {
return;
}
// use a hash set to mark visited nodes
Set<GraphNode> set = new HashSet<GraphNode>();
// use a stack to help depth-first traversal
Stack<GraphNode> stack = new Stack<GraphNode>();
stack.push(node);
while (!stack.isEmpty()) {
GraphNode curr = stack.pop();
// current node has not been visited yet
if (!set.contains(curr)) {
// visit the node
// ...
// mark it as visited
set.add(curr);
}
for (int i = 0; i < curr.neighbors.size(); i++) {
GraphNode neighbor = curr.neighbors.get(i);
// this neighbor has not been visited yet
if (!set.contains(neighbor)) {
stack.push(neighbor);
}
}
}
}
We can use the same logic to do DFS recursively, clone graph etc.
Many people will say that non-recursive DFS is just BFS with a stack rather than a queue. That's not accurate, let me explain a bit more.
Recursive DFS
Recursive DFS uses the call stack to keep state, meaning you do not manage a separate stack yourself.
However, for a large graph, recursive DFS (or any recursive function that is) may result in a deep recursion, which can crash your problem with a stack overflow (not this website, the real thing).
Non-recursive DFS
DFS is not the same as BFS. It has a different space utilization, but if you implement it just like BFS, but using a stack rather than a queue, you will use more space than non-recursive DFS.
Why more space?
Consider this:
// From non-recursive "DFS"
for (auto i&: adjacent) {
if (!visited(i)) {
stack.push(i);
}
}
And compare it with this:
// From recursive DFS
for (auto i&: adjacent) {
if (!visited(i)) {
dfs(i);
}
}
In the first piece of code you are putting all the adjacent nodes in the stack before iterating to the next adjacent vertex and that has a space cost. If the graph is large it can make a significant difference.
What to do then?
If you decide to solve the space problem by iterating over the adjacency list again after popping the stack, that's going to add time complexity cost.
One solution is to add items to the stack one by one, as you visit them. To achieve this you can save an iterator in the stack to resume the iteration after popping.
Lazy way
In C/C++, a lazy approach is to compile your program with a larger stack size and increase stack size via ulimit, but that's really lousy. In Java you can set the stack size as a JVM parameter.
Recursion is a way to use the call stack to store the state of the graph traversal. You can use the stack explicitly, say by having a local variable of type std::stack, then you won't need the recursion to implement the DFS, but just a loop.
okay. if you are still looking for a java code
dfs(Vertex start){
Stack<Vertex> stack = new Stack<>(); // initialize a stack
List<Vertex> visited = new ArrayList<>();//maintains order of visited nodes
stack.push(start); // push the start
while(!stack.isEmpty()){ //check if stack is empty
Vertex popped = stack.pop(); // pop the top of the stack
if(!visited.contains(popped)){ //backtrack if the vertex is already visited
visited.add(popped); //mark it as visited as it is not yet visited
for(Vertex adjacent: popped.getAdjacents()){ //get the adjacents of the vertex as add them to the stack
stack.add(adjacent);
}
}
}
for(Vertex v1 : visited){
System.out.println(v1.getId());
}
}
Python code. The time complexity is O(V+E) where V and E are the number of vertices and edges respectively. The space complexity is O(V) due to the worst-case where there is a path that contains every vertex without any backtracking (i.e. the search path is a linear chain).
The stack stores tuples of the form (vertex, vertex_edge_index) so that the DFS can be resumed from a particular vertex at the edge immediately following the last edge that was processed from that vertex (just like the function call stack of a recursive DFS).
The example code uses a complete digraph where every vertex is connected to every other vertex. Hence it is not necessary to store an explicit edge list for each node, as the graph is an edge list (the graph G contains every vertex).
numv = 1000
print('vertices =', numv)
G = [Vertex(i) for i in range(numv)]
def dfs(source):
s = []
visited = set()
s.append((source,None))
time = 1
space = 0
while s:
time += 1
current, index = s.pop()
if index is None:
visited.add(current)
index = 0
# vertex has all edges possible: G is a complete graph
while index < len(G) and G[index] in visited:
index += 1
if index < len(G):
s.append((current,index+1))
s.append((G[index], None))
space = max(space, len(s))
print('time =', time, '\nspace =', space)
dfs(G[0])
Output:
time = 2000
space = 1000
Note that time here is measuring V operations and not E. The value is numv*2 because every vertex is considered twice, once on discovery and once on finishing.
Acutally, stack is not well able to deal with discover time and finish time, if we want to implement DFS with stack, and want to deal with discover time and finish time, we would need to resort to another recorder stack, my implementation is shown below, have test correct, below is for case-1, case-2 and case-3 graph.
from collections import defaultdict
class Graph(object):
adj_list = defaultdict(list)
def __init__(self, V):
self.V = V
def add_edge(self,u,v):
self.adj_list[u].append(v)
def DFS(self):
visited = []
instack = []
disc = []
fini = []
for t in range(self.V):
visited.append(0)
disc.append(0)
fini.append(0)
instack.append(0)
time = 0
for u_ in range(self.V):
if (visited[u_] != 1):
stack = []
stack_recorder = []
stack.append(u_)
while stack:
u = stack.pop()
visited[u] = 1
time+=1
disc[u] = time
print(u)
stack_recorder.append(u)
flag = 0
for v in self.adj_list[u]:
if (visited[v] != 1):
flag = 1
if instack[v]==0:
stack.append(v)
instack[v]= 1
if flag == 0:
time+=1
temp = stack_recorder.pop()
fini[temp] = time
while stack_recorder:
temp = stack_recorder.pop()
time+=1
fini[temp] = time
print(disc)
print(fini)
if __name__ == '__main__':
V = 6
G = Graph(V)
#==============================================================================
# #for case 1
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(2,1)
# G.add_edge(3,2)
#==============================================================================
#==============================================================================
# #for case 2
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(3,2)
#==============================================================================
#for case 3
G.add_edge(0,3)
G.add_edge(0,1)
G.add_edge(1,4)
G.add_edge(2,4)
G.add_edge(2,5)
G.add_edge(3,1)
G.add_edge(4,3)
G.add_edge(5,5)
G.DFS()
I think you need to use a visited[n] boolean array to check if the current node is visited or not earlier.
A recursive algorithm works very well for DFS as we try to plunge as deeply as we can, ie. as soon as we find an un-explored vertex, we're going to explore its FIRST un-explored neighbor right away. You need to BREAK out of the for loop as soon as you find the first un-explored neighbor.
for each neighbor w of v
if w is not explored
mark w as explored
push w onto the stack
BREAK out of the for loop
I think this is an optimized DFS regarding space-correct me if I am wrong.
s = stack
s.push(initial node)
add initial node to visited
while s is not empty:
v = s.peek()
if for all E(v,u) there is one unvisited u:
mark u as visited
s.push(u)
else
s.pop
Using Stack and implementing as done by the call stack in the recursion process-
The Idea is to push a vertex in the stack, and then push its vertex adjacent to it which is stored in a adjacency list at the index of the vertex and then continue this process until we cannot move further in the graph, now if we cannot move ahead in the graph then we will remove the vertex which is currently on the top of the stack as it is unable to take us on any vertex which is unvisited.
Now, using stack we take care of the point that the vertex is only removed from the stack when all the vertices that can be explored from the current vertex have been visited, which was being done by the recursion process automatically.
for ex -
See the example graph here.
( 0 ( 1 ( 2 ( 4 4 ) 2 ) ( 3 3 ) 1 ) 0 ) ( 6 ( 5 5 ) ( 7 7 ) 6 )
The above parenthesis show the order in which the vertex is added on the stack and removed from the stack, so a parenthesis for a vertex is closed only when all the vertices that can be visited from it have been done.
(Here I have used the Adjacency List representation and implemented as a vector of list (vector > AdjList) by using C++ STL)
void DFSUsingStack() {
/// we keep a check of the vertices visited, the vector is set to false for all vertices initially.
vector<bool> visited(AdjList.size(), false);
stack<int> st;
for(int i=0 ; i<AdjList.size() ; i++){
if(visited[i] == true){
continue;
}
st.push(i);
cout << i << '\n';
visited[i] = true;
while(!st.empty()){
int curr = st.top();
for(list<int> :: iterator it = AdjList[curr].begin() ; it != AdjList[curr].end() ; it++){
if(visited[*it] == false){
st.push(*it);
cout << (*it) << '\n';
visited[*it] = true;
break;
}
}
/// We can move ahead from current only if a new vertex has been added on the top of the stack.
if(st.top() != curr){
continue;
}
st.pop();
}
}
}
The following Java Code will be handy:-
private void DFS(int v,boolean[] visited){
visited[v]=true;
Stack<Integer> S = new Stack<Integer>();
S.push(v);
while(!S.isEmpty()){
int v1=S.pop();
System.out.println(adjLists.get(v1).name);
for(Neighbor nbr=adjLists.get(v1).adjList; nbr != null; nbr=nbr.next){
if (!visited[nbr.VertexNum]){
visited[nbr.VertexNum]=true;
S.push(nbr.VertexNum);
}
}
}
}
public void dfs() {
boolean[] visited = new boolean[adjLists.size()];
for (int v=0; v < visited.length; v++) {
if (!visited[v])/*This condition is for Unconnected Vertices*/ {
System.out.println("\nSTARTING AT " + adjLists.get(v).name);
DFS(v, visited);
}
}
}
I have a directed acyclic graph on which every vertex has a weight >= 0. There is a vertex who is the "start" of the graph and another vertex who is the "end" of the graph. The idea is to find the path from the start to the end whose sum of the weights of the vertices is the greater. For example, I have the next graph:
I(0) -> V1(3) -> F(0)
I(0) -> V1(3) -> V2(1) -> F(0)
I(0) -> V3(0.5) -> V2(1) -> F(0)
The most costly path would be I(0) -> V1(3) -> V2(1) -> F(0), which cost is 4.
Right now, I am using BFS to just enumerate every path from I to F as in the example above, and then, I choose the one with the greatest sum. I am afraid this method can be really naive.
Is there a better algorithm to do this? Can this problem be reduced to another one?
Since your graph has no cycles* , you can negate the weights of your edges, and run Bellman-Ford's algorithm.
* Shortest path algorithms such as Floyd-Warshall and Bellman-Ford do not work on graphs with negative cycles, because you can build a path of arbitrarily small weight by staying in a negative cycle.
You can perform a topological sort, then iterate through the list of vertices returned by the topological sort, from the start vertex to the end vertex and compute the costs. For each directed edge of the current vertex check if you can improve the cost of destination vertex, then move to the next one. At the end cost[end_vertex] will contain the result.
class grph:
def __init__(self):
self.no_nodes = 0
self.a = []
def build(self, path):
file = open(path, "r")
package = file.readline()
self.no_nodes = int(package[0])
self.a = []
for i in range(self.no_nodes):
self.a.append([10000] * self.no_nodes)
for line in file:
package = line.split(' ')
source = int(package[0])
target = int(package[1])
cost = int(package[2])
self.a[source][target] = cost
file.close()
def tarjan(graph):
visited = [0] * graph.no_nodes
path = []
for i in range(graph.no_nodes):
if visited[i] == 0:
if not dfs(graph, visited, path, i):
return []
return path[::-1]
def dfs(graph, visited, path, start):
visited[start] = 1
for i in range(graph.no_nodes):
if graph.a[start][i] != 10000:
if visited[i] == 1:
return False
elif visited[i] == 0:
visited[i] = 1
if not dfs(graph, visited, path, i):
return False
visited[start] = 2
path.append(start)
return True
def lw(graph, start, end):
topological_sort = tarjan(graph)
costs = [0] * graph.no_nodes
i = 0
while i < len(topological_sort) and topological_sort[i] != start:
i += 1
while i < len(topological_sort) and topological_sort[i] != end:
vertex = topological_sort[i]
for destination in range(graph.no_nodes):
if graph.a[vertex][destination] != 10000:
new_cost = costs[vertex] + graph.a[vertex][destination]
if new_cost > costs[destination]:
costs[destination] = new_cost
i += 1
return costs[end]
Input file:
6
0 1 6
1 2 2
3 0 10
1 4 4
2 5 9
4 2 2
0 2 10
In general longest path problem is NP-hard, but since the graph is a DAG, it can be solved by first negating the weights then do a shortest path. See here.
Because the weights reside on the vertices, before computing, you might want to move the weights to the in edges of the vertices.