counting total degrees of a graph - algorithm

In a directed graph, the total degree of a node is the number of edges going into it plus the number of edges going out of it. Give a linear-time algorithm that takes as input a directed graph (in adjacency list format, as always), and computes the total degree of every node. The output of the algorithm should be an array total[.], with an entry for each node.
this is my pseudo-code for this problem:
procedure total degree(G)
Input: Directed graph G=(V,E)
Output: array total[.] with an entry for each node
for all u in V in[u]=0
for all u in V:
for all (u,v) in E:
in[v]=in[v]+1
for all u in V out[u]=0
for all u in V:
for all (u,v) in E:
out[u]=out[u]+1
for all u in V total[u]=0
for all u in V:
total[u]=in[v]+out[u]
return total[u]
can someone concur i did this right or tell me what i need to fix if i made a mistake, what im really unsure about is if i did the outdegrees (out[.]) right
i used this code as a reference point to come up with my own:
function sources(G)
Input: Directed graph G = (V;E)
Output: A list of G's source nodes
for all u in V : in[u] = 0
for all u in V :
for all edges (u,w) in E:
in[w] = in[w] + 1
L = empty linked list
for all u in V :
if in[u] is 0: add u to L
return L

Your second for block is the same as the first one, the only difference being the array name. This means it's going to count the same edges as the first one, giving you a wrong result.
In your second for, you need to count the other edge, not the same one:
for all u in V out[u]=0
for all u in V:
for all (u,v) in E:
out[v]=out[v]+1
Alternatively, you could count them all in one go:
Assuming input G=(V,E) is a list of nodes (V) and a list of edges (E) represented by node pairs ((u, v)), and assuming duplicates should count, all you need to do is count the nodes (both out and in) in the edge list.
for all u in V
total[u] = 0
for all (u, v) in E
total[u] = total[u] + 1
total[v] = total[v] + 1
return total

Related

Find all pairs of nodes whose deletion disconnects graph

Given undirected, connected graph, find all pairs of nodes (connected by an edge) whose deletion disconnects the graph.
No parallel edges and no edges connecting node to itself.
The problem seems similar to finding articulation points (or bridges) of a connected, undirected graph - yet with a twist, that we have to remove a pair of vertices connected by an edge (and all other edges connected to that pair).
This is a homework question. I've been trying to solve it, read about DFS and articulation points algorithms (that bookkeap depth and lowpoint of each node) - but none of these approaches help this particular problem. I've checked through Cormen's Intro to Algorithms, but no topic suggested itself as appropriate (granted, book does have 1500 pages).
While it's true that finding articulation point would also (most of the time) find such a pair, there are a lot of pairs that are not articulation points - consider a graph with 4-vertices,5-edges (square with a single diagonal): it has one such pair but no articulation points (nor bridges).
I'm lost. Help me, stack overflow, you are my only hope.
Rather straightforward, maybe not the most efficient:
Let the graph be G=(V,E) with V := {v_1, ..., v_n}. For each subset V' of V let G_V' be the node induced subgraph comprising the nodes V \ V'. Let further N>_v_i := {v_j in V : {v_i,v_j} in E and j > i} be the set of all neighbors of v_i in G with index greater than i. Finally, let c(G) be the set of connected components of a graph.
Compute the pairs as follows:
pairs = {}
for each v in V:
compute G_{v}
if G_{v} is unconnected:
for each v' in N>_v:
# Ensures that removal of v' does not render subgraph connected
# (Note comment by MkjG)
if |c(G_{v})| > 2 or {v'} not in c(G_{v}):
add {v,v'} to pairs
else:
for each v' in N>_v:
compute G_{v,v'}
if G_{v,v'} unconnected:
add {v,v'} to pairs
Connectivity can be checked via DFS or BFS in O(m+n). The runtime should hence be O(n * k * (m+n)), where k is the maximum degree of G.
Update to my previous answer based on the suggestion by #MkjG to use DFS for computing articulation points.
Let the graph be G=(V,E) with V := {v_1, ..., v_n}_. For each subset V' of V let G_V' be the node induced subgraph comprising the nodes V \ V'. For G connected, we call v in V an articulation point if G_{v} is unconnected. Let N_v be the set of neighbors of v in G.
Articulation points can be computed via DFS, read here for more information on the algorithm. In short:
compute a DFS tree T for some root node r in V
r is an articulation point, iff it has more than one child in T
any other node v in V is an articulation point, iff it has a child v' in T that satisfies the following condition: no node in the subtree T' of T rooted at v' has a back edge to an ancestor of v
Let the result of a DFS on graph G be a function c on the nodes v in V. c(v) is a subset of N_v, it holds v' in c(v) iff both of the following conditions are met:
v' is a child of v in T
no node in the subtree T' of T rooted at v' has a back edge to an ancestor of v
Note that for the root node r of T, c(r) is the set of all children of r. Function c can be computed in time O(n+m).
Compute the separator pairs as follows:
# performs DFS on G for some root node r
c = DFS(G,r)
# computes articulation points of G and corresponding number of components
aps = {}
compCounts = {}
for each v in V:
numComps = |c(v)|
if v != r:
++numComps
if numComps > 1:
add v to aps
compCounts[v] = numComps
# computes the set of all separator pairs containing at least on ap
S = {}
for each v in aps:
numComps = compCounts[v]
for each v' in N_v:
if numComps > 2:
# G_{v,v'} has at least two connected components
add {v,v'} to S
else:
# if v' is an isolated node in G_{v}, then G_{v,v'} is connected
if N_v' != {v}:
add {v,v'} to S
# computes remaining separator pairs
for each v in V \ aps:
compute G_{v}
# performs DFS on G_{v} for some root r_v != v
c_v = DFS(G_{v},r_v)
# adds separator pairs for articulation points of G_{v} in N_v
for each v' in N_v:
numComps = |c(v')|
if v' != r_v:
++numComps
if numComps > 1:
add{v,v'} to S
Runtime is in O(n * (n+m))
A set of k edges disconnecting a graph is called a k-cut. You are trying to enumerate all 2-cuts of a graph.
This paper describes an efficient algorithm to enumerate all cuts of a graph. It should be possible to adapt it to find all 2-cuts of a graph.

How to count all reachable nodes in a directed graph?

There is a directed graph (which might contain cycles), and each node has a value on it, how could we get the sum of reachable value for each node. For example, in the following graph:
the reachable sum for node 1 is: 2 + 3 + 4 + 5 + 6 + 7 = 27
the reachable sum for node 2 is: 4 + 5 + 6 + 7 = 22
.....
My solution: To get the sum for all nodes, I think the time complexity is O(n + m), the n is the number of nodes, and m stands for the number of edges. DFS should be used,for each node we should use a method recursively to find its sub node, and save the sum of sub node when finishing the calculation for it, so that in the future we don't need to calculate it again. A set is needed to be created for each node to avoid endless calculation caused by loop.
Does it work? I don't think it is elegant enough, especially many sets have to be created. Is there any better solution? Thanks.
This can be done by first finding Strongly Connected Components (SCC), which can be done in O(|V|+|E|). Then, build a new graph, G', for the SCCs (each SCC is a node in the graph), where each node has value which is the sum of the nodes in that SCC.
Formally,
G' = (V',E')
Where V' = {U1, U2, ..., Uk | U_i is a SCC of the graph G}
E' = {(U_i,U_j) | there is node u_i in U_i and u_j in U_j such that (u_i,u_j) is in E }
Then, this graph (G') is a DAG, and the question becomes simpler, and seems to be a variant of question linked in comments.
EDIT previous answer (striked out) is a mistake from this point, editing with a new answer. Sorry about that.
Now, a DFS can be used from each node to find the sum of values:
DFS(v):
if v.visited:
return 0
if v is leaf:
return v.value
v.visited = true
return sum([DFS(u) for u in v.children])
This is O(V^2 + VE) worst vase, but since the graph has less nodes, V
and E are now significantly lower.
Some local optimizations can be made, for example, if a node has a single child, you can reuse the pre-calculated value and not apply DFS on the child again, since there is no fear of counting twice in this case.
A DP solution for this problem (DAG) can be:
D[i] = value(i) + sum {D[j] | (i,j) is an edge in G' }
This can be calculated in linear time (after topological sort of the DAG).
Pseudo code:
Find SCCs
Build G'
Topological sort G'
Find D[i] for each node in G'
apply value for all node u_i in U_i, for each U_i.
Total time is O(|V|+|E|).
You can use DFS or BFS algorithms for solving Your problem.
Both have complexity O(V + E)
You dont have to count all values for all nodes. And you dont need recursion.
Just make something like this.
Typically DFS looks like this.
unmark all vertices
choose some starting vertex x
mark x
list L = x
while L nonempty
choose some vertex v from front of list
visit v
for each unmarked neighbor w
mark w
add it to end of list
In Your case You have to add some lines
unmark all vertices
choose some starting vertex x
mark x
list L = x
float sum = 0
while L nonempty
choose some vertex v from front of list
visit v
sum += v->value
for each unmarked neighbor w
mark w
add it to end of list

How to find the sum weight of all edges reachable from some vertex?

Consider a directed graph with no cycles. I need to find for each u the total weight of edges reachable from u (by reachable we mean there's a path from u to some v).
Now, what I thought about is running topological sort and then starting to run from the last node to the first node (possible by interchanging the direction of the edges)
And then we're evaluating f[v] = f[u] + w(u,v).
but there's a problem; for this graph, we will count f[d] twice. How can I overcome this?
You can use either BFS or DFS to achieve this.
total = 0
dfs (node):
if visited[node] == 1:
return
visited[node] = 1
for all u connected to node:
total += weight[node][u]
dfs(u)
Note that we check the visited after total += weight[node][u].
You can use a bottom up approach. that is firstly calculate the outdegree of each vertex, Now the vertices with 0 outdegree would have F[u] = 0 for them. Now add all such vertices in a queue Q.
Also you would need to store the transpose of the Graph, suppose it was T.
While(!Q.empty){
u=Q.front();
Q.pop();
for all edges E originating from T[u]{
F[v]+=w; (where (u,v) was the edge with w as weight)
//now remove u from the graph
outdegree[v]--;
if(outdegree[v]==0)
Q.push(v);
}
}

A function definition for directed acyclic graphs

Let's consider the following problem: For a directed acyclic graph G = (V,E) we define the function "levels" for each vertex u, as l(u) such that:
1. l(u)>=0 for every u
2. If there is a path from u to v (u -> v) then l(u)>l(v)
3. For each vertex u, l(u) is the minimum integer that satisfies both conditions 1 and 2.
The problem says:
a. Prove that for every DAG the above function is uniquely defined, i.e. it's the only function that satisfies conditions 1,2 and 3.
b. Find an O(|V| + |E|) algorithm that calculates this function for every vertex.
Here is a possible algorithm based on topological sort:
First we find the transpose of G which is G^T, defined as G^T = (V,E^T), where E^T={(u,v): (v,u) is in E} which takes O(|V|+|E|) in total if based on adjacency list implementation:
(O(|V|) for allocation and sum for all v in V of |Adj[v]| = O(|E|)). Topological sort takes Theta(|V|+|E|) since it includes a BFS and |V| insertions in list each of which take O(1).
TRANSPOSE(G){
Allocate |V| list pointers for G^T i.e. (Adj'[])
for(i = 1, i <= |V|, i++){
for every vertex v in Adj[i]{
add vertex i to Adj'[v]
}
}
}
L = TopSort(G)
a. Prove that for every DAG the above function is uniquely defined, i.e. it's the only function that satisfies conditions 1,2 and 3.
Maybe I am missing something, but this seems really obvious to me: if you define it as the minimum that satisfies those conditions, how can there be more than one?
b. Find an O(|V| + |E|) algorithm that calculates this function for every vertex.
I think your topological sort idea is correct (note that a topological sort is a BFS), but it should be performed on the transposed graph (reverse the direction of every edge). Then the first values in the topological sort get 0, the next get 1 etc. For example, for the transposed graph:
1 2 3
*-->*-->*
^
*-------|
1
I have numbered the nodes with their positions in the topological sort. You number the nodes by implementing the topological sort using a BFS. When you extract a node from your FIFO queue, you subtract 1 from the indegree of all of its reachable nodes. When that indegree becomes 0 you insert the node it became 0 for in the queue and you number it as exracted_node + 1. In my example, the nodes numbered 1 start with indegree 0. Then, the bottom-most 1 subtract one from the indegree of the node labeled 3, but that indegree will be 1, not zero, so we don't insert it in the queue. We insert 2 however because its indegree will become 0.
Pseudocode:
G = G^t
Q = a FIFO queue
push all nodes with indegree 0 in Q
set l(v) = 0 for all nodes with indegree 0
indegree(v) = how many edges are going into node v
while not Q.Empty():
x = Q.Pop()
for all nodes v reachable from x:
if indegree[v] > 0:
indegree[v] = indegree[v] - 1
if indegree[v] == 0:
Q.Push(v)
l[v] = l[x] + 1
You can also do it with a DFS that computes the value of each node once the recursion returns, as:
value(v) = 1 + max{value(c), c a child of v}
Note that the DFS is not dont on the transposed graph, because we'll let the recursion handle the traversal in topological sort order.
Let's say you have a topological sort of G. Then you can consider vertices in reversed order: if you have a u -> v edge, then v comes before u in ordering.
If you loop on the nodes with this order, then let l(u) = 0 if there is no outgoing edges and l(u) = 1 + max(l(v), for each v such that there is an edge (u, v)). This is optimal and give you an O(|V| + |E|) algorithm to solve this problem.
Proof is left as an exercise. :D

return source nodes of a directed graph

A source in a directed graph is a node that has no edges going into it. Give a linear-time algorithm
that takes as input a directed graph in adjacency list format, and outputs all of its sources.
solution:
Finding the sources of a directed graph.
We will keep an array in[u] which holds the indegree (number of incoming edges) of each node. For a
source, this value is zero.
function sources(G)
Input: Directed graph G = (V,E)
Output: A list of G's source nodes
for all u ∈ V : in[u] = 0
for all u ∈ V :
for all edges (u,w) ∈ E:
in[w] = in[w] + 1
L = empty linked list
for all u ∈ V :
if in[u] is 0: add u to L
return L
the thing i particularly do not understand about the code above is the innermost for loop in the first code block what exactly does in[w] = in[w]+1 mean? i think it means its counting the indegrees of each node, but how exactly it's doing that i cannot picture it, can someone please help me visualize this aspect
in[w] = in[w] + 1 increases the number of edges going into w.
Maybe an example will help:
Consider a simple graph:
a ---> b
The adjacency list representation is:
a: {b}
b: {}
Now the algorithm will loop through all vertices.
For a, it will loop over the edge (a,b) and increase b's count.
For b, there are no edges.
Now a's count is still zero, thus it is a source vertex.

Resources