User:Zelhar/Algorithms1 maman13



1.1
claim 1.1: G contains a cycle iff There's a back-edge discovered during the execution of DFS(G) Proof: A back edge (u,v) is an edge from v to a predecessor u, in the DEFS tree, and thus together with the path of tree edges from u to v it closes a cycle. In the other direction- if there are no back-edges than all the edges are tree-edges (since there are only these two kinds in the case of an undirected graph), and so DFS(G) produces a forest, which has no cycles.

It follows that to find out if there's a cycle in G, we can run DFS and stop it immediately after the discovery of the first back edge. The running time is O(n), proof: case1- No back edges were discovered: in this case the algorithm completes its running exactly like the normal DFS, and the forest it produces contains all the edges in E, and takes time O(E). But then G is a forest, and for each tree we know that |E| = |V|-1, and since the trees in the forest are disjoint, it follows that |E| = O(|V|) in G. case2- A a first back edge is discovered: Up to the moment of the discovery, DFS has created a forest that is a sub-graph of G=(V,E), and thus by case 1 the running time had been so far O(V), and since the algorithm stops immediately afterwards, its terminal running time remains O(v).

Here is the algorithm explicitly: DFS-Cycle(G) cycle = FALSE for (v &isin; V): color[v] = WHITE &pi;[v] = NIL time = 0 for (v &isin; V): if (color[v] == WHITE): cycle = DFS-Visit-Cycle(v) if (cycle == TRUE): return TRUE return FALSE

DFS-Visit-Cycle(u) color[u] = GRAY time = time + 1 d[u] = time for (v in Adj[u]): if (color[v] == WHITE): &pi;(v) = u               DFS-Visit-Cycle(v) else-if (color[v] == GRAY): //(u,v) is a back edge, so a cycle exists and we can stop searching. return TRUE color[u] = BLACK time = time + 1 f[u] = time return FALSE

1.2
Correct, proof: let u and v be vertices in the DFS tree connected by an edge. Assume (WLG) that u was discovered before v. Then once u is discovered, v is still white, and all of u's descendants In the Tree are scanned and discovered. Any white descendant of u is discovered and its rank is strictly greater than that of u. At the moment v is discovered there is a white path leading from u to v, since by the DFS algorithm, v is first discovered as a child to a white descendant of u, or as a child of u. That's because (u,v) is an edge and v was white when u had been discovered, so v must be discovered during one of the recursive calls to DFS-Visit(x) inside DFS-Visit(u), And they are only called in the case that x is white. It follows that v is a descendant of u in the DFS tree and thus its rank is strictly greater than u's. It follows that if u and v are of equal ranks, they are not connected by an edge.

P2
A formula to calculate D(x): If x is not a separation vertice then at its removal G remains connected, so D(x)=1. If x is a separation vertice, then each adjacent node v such that L(v)>=d[x] is disconnected from the tree above it and from the subtrees stemming from x, For there are only tree and back edges in an undirected graph. if x is removed, and hence belongs to a connected component of its own. Hence each adjacent v with L(v)>=d[x] contributes 1 new component, any other adjacent v, belongs to the same component of the root t. This argument is correct for all vertices other than the root t. For t we have: D[t] = |Adj[t]| by removing t, any tree stemming from t forms its own component. So The following algorithm will return D[t] that is greater by 1 than the real value D[t] should be.

The adjusted algorithm is therefore:

DFS-VL-D(u) color[u] = GRAY D[u] = 1 time = time + 1 d[u] = time L(u) = d[u] for (v &isin; Adj[u]): if (color[v] == WHITE): &pi;(v) = u               DFS-VL-D(v) if (L(v) >= d[u]): D[u] = D[u] + 1 L(u) = min{L(u),L(v)} else-if (v != &pi;(u)): L(u) = min{L(u),d[v]} color[u] = BLACK time = time + 1 f[u] = time //When the algorithm has finished, D[t] should be decreased by 1, where t is   //the root. For removal of t also removes the component of t itself.

The running time remains the same as that of DFS-VL since for each vertice x, D[x] is updated no more than 1+d times, where d is the degree of x, and so the total number of updating on account for all vertices is O(E), which doesn't change the original &theta;(E) running time.

P3
for the span of this exercise, for all e=(u,v) &isin; E, let pe denote a path in E from v to u (in case we know such path exists).  'only if' direction: if G is strongly connected, for every e=(u,v) &isin; E we are assured the existence of a directed path pe from v to u, and together, e and pe form a directed cycle, hence every edge belongs to a directed cycle. Moreover, if G is strongly connected, then obviously G' is connected.

if direction: let u,v &isin; E. let p' = (e'1,...,e'k) be a path in G' between u and v. for each ei &isin; E', let ei &isin; E be a directed edge between the same vertices of e'i (we are assured that such edge exists by the definition of G'). Give the path p', and every edge in it an orientation from u to v. for i=1..k, let fi = ei if the orientation of e'i is the same as that of ei, and fi = pe' i otherwise (such path exists because ei belongs to a directed cycle). Then each fi is a path with the same orientation, and combined together, f1,...,fk form a path from u to v. This proves that for every pair of vertices u,v &isin; E, there is a directed path from u to v, and since u,v are arbitrarily chosen, then any vertice can be connected to any other vertice, in a directed path, hence G is strongly connected.

4.1
True: If e = (u,v) belongs to a cycle, then after removing e, G is still connected- there is a path p connecting u and v (that closes a cycle with e), so any in any path p' that contains e, e can be replaced with p, and so e is not a bridge. If no cycle contains e = (u,v), then there is no path p, other than e, connecting u and v, for if such p existed, then it would have closed a cycle with e, in contradiction to the premise. And so by removing e, there's no path connecting u and v, hence G - e is disconnected, and e is a bridge.

4.2
True: Let G'=(V,E') be the bridge graph of G=(V,E). If e &isin; E' then there is no cycle In G contains e (by 4.1), but G' is a subgraph of G, so clearly no cycle in G' contains e. But this holds for all edges in E', and so G' has no cycles.

4.3
No: Let G=(V,E): V={1,2}, E={(1,2)}. Then G-{1} and G-{2} are 'graphs' on one vertice with no edges, and they are trivially connected, hence no vertice of G is a separation vertice. But the edge e=(1,2) is a bridge- its removal creates a disconnected graph on two vertices.

4.4
No: Let G=(V,E), V={0,1,2,3,4}, E={(1,2),(3,4),(0,1),(0,2),(0,3),(0,4)} Then 0 is a separation vertice, but no edge in E is a bridge.

P5
claim 5.1: G is semi connected iff G' := GSCC is semi connected proof: for v &isin; V let [v] denote the connected component of v, (so [v] is a node in G'. By definition, ([u],[v]) &isin; V' (where G' = (V',E')) iff there are x &isin; [u], y &isin; [v] and (u,v) &isin; V, and since [u], [v] are strongly connected component, there are paths u-->x, y-->v, and so there is a path from u to v. Given a path in G' [u]-->[v], by applying the above method on every edge in the path, it can be shown that there is a path u-->v in G. If u-->v is a path in G, then a corresponding path [u]-->[v] exists in G, This easily follows from G' definitions. if u=v then the path in G' is [u] itself, and if u &isin; [v] then there is u-->v since they are in the same component. The above observations proves that: u and v are connected by a path in G iff [u] and [v] are connected by a path in G', and so G is semi connected iff G' is semi connected.

claim 5.2: If G is a dag, then G is semi connected iff there is a directed path containing all the vertices of G proof: Let G be semi connected. rearragnge G in topological order, let v1, ..., vn be its vertices from left to right. If j>i, then there is no path from vj to vi, since that would contradict the order, hence G is semi connected iff for all j>i, there's a directed path from vi to vj, which in turn implies that there is a path from v1 to vn containing all the vertices on the way. The other direction is trivial- if there is such a path, then clearly G is semi connected.

claim 5.3: If G is a topologically sorted dag, then the only possible path that passes through all the vertices is v1v2...vn Proof: for each edge (vi,vj) in the path we have i < k because the vi's are topologically sorted, so j >= i+1. (G is a acyclic, so i = j is also impossible). if j > i+1, then vi+1 can't belong to the path. But the path has length >= n-1, since it has all the vertices, and so it follows that the only possible path to pass through all the vertices is the path of length = n-1 of the form v1v2...vn

The required algorithms would therefore work as follows:

Check-Semi-Connection(G) G' = Build-Component-Graph(G) //See this function bellow Topological-Sort(G') //assume that v[1],...,v[k] are the the vertices sorted topologically i = 1 while (i<k and (i+1) &isin; Adj[v[i]]): i = i+1 if (i == n): return TRUE else: return FALSE

Input G = (V,E), V = [1,...,n], E = e[1,...,m] = An array of all the edges, Adj[i] = [a linked list of a subset of V]

Build-Component-Graph(G) Strongly-Connected-Component(G) »use count-sort to build v[1...n] a permutation of V, such that »d[v[1]] < d[v[2]] < ... < d[v[n]] //basically sort V according to the time stamp d[], //where d[] is the time stamp of the second call to DFS in the //Strongly-Connected-Component(G) function. k = 1 c[v[1]] = k       for (i = 2 to n): if (d[v[i]] > f[v[k]]): k = k + 1 //v[i] is the root of a new component c[v[i]] = k       »Create an empty list L        for (i = 1 to n): for (j in Adj[i]): if (c[i] != c[j]): »insert (c[i],c[j]) to L       //each pair in L is regarded as a 2-digit base-n number »Radix-Sort L and erase duplicated elements »create and empty array H[1...k] of empty lists for ( (u,v) in L): »insert v to list H[u] V' = [1...k]       G' = (V',H) return G'        //Now H is the Adjacency lists of the component //graph on vertices [1...k]

The running time for Build-Component-Graph is &theta;(V + E): Strongly-Connected-Component is known to take &theta;(V+E) time. counting-sorting V takes O(V) since max{d[i]}i&isin;V = O(n). radix-sorting E takes O(2(E + V)) = O(V+E) (|E| 2-digit base-n numbers). Each of the loops in the algorithm either scans V or E so they take O(V+E) time. In all, the running time is &theta;(V+E)

Correctness of Build-Component-Graph: As is already known, After execution of Storngly-Connected-Component, The time stamps have a parenthesis structure, such that the each componenet is corresponding to a maximal-nesting parenthesis structure. The algorithm identify to which component each vertice belongs according to the parenthesis structure, creates a representation to each component, and then it builds the adjoint list to each representative.

The correctness of the algorithm follows from claims 5.1 - 5.3: G' is built from G. G' is acyclic and so it can be topologically ordered. Then All that is left to check is if there is a path v1, v2, ..., vn since it's the only possible path in a topologically ordered dag that passes through every vertice. Claim 5.2 assures that G' is semi connected iff such path exists. Claim 5.1 assures that G' is semi connected iff G is semi connected, and so the algorithm is correct.

Asymptotic Running Time: Build-Component(G) takes &theta;(V+E) (see above) ,Topological-Sort(G) also takes &theta;(V+E). Since the number of components is O(V), the while loop takes O(V) time, and in total the algorithms takes &theta;(V+E) time.

