Graph Algorithms-Datastructues and Algorithms-Solutions, Exercises of Data Structures and Algorithms

This is solution manual provided by Muhammad Uzair at University of Engineering and Technology Lahore. It related to Data Structures and Algorithms course. Its main points are: Graph, Algorithm, Queue, Adjacency, List, Weighted, Paths, Dijkstra, Path, Array, Tiebreaker

Typology: Exercises

2011/2012

Uploaded on 07/16/2012

sangodkar
sangodkar 🇵🇰

5

(2)

12 documents

1 / 12

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Data Structures & Algorithm Analysis in C
(second edition)
MarkAllenWeiss
FloridaInternationalUniversity
SolutionsManual
By:
Muhammad Uzair
05-E-147
U.E.T. Lahore
Pakistan
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Graph Algorithms-Datastructues and Algorithms-Solutions and more Exercises Data Structures and Algorithms in PDF only on Docsity!

Data Structures & Algorithm Analysis in C

(second edition)

MarkAllenWeiss

FloridaInternationalUniversity

SolutionsManual

By:

Muhammad Uzair

05-E-

U.E.T. Lahore

Pakistan

[email protected]

Preface

Included in this manual are answers to most of the exercises in the textbook Data Structures and Algorithm Analysis in C, second edition, published by Addison-Wesley. These answers reflect the state of the book in the first printing.

Specifically omitted are likely programming assignments and any question whose solu- tion is pointed to by a reference at the end of the chapter. Solutions vary in degree of complete- ness; generally, minor details are left to the reader. For clarity, programs are meant to be pseudo-C rather than completely perfect code.

Errors can be reported to [email protected]. Thanks to Grigori Schwarz and Brian Harvey for pointing out errors in previous incarnations of this manual.

Chapter 9: Graph Algorithms

9.1 The following ordering is arrived at by using a queue and assumes that vertices appear on an adjacency list alphabetically. The topological order that results is then s, G, D, H, A, B, E, I, F, C, t

9.2 Assuming the same adjacency list, the topological order produced when a stack is used is s, G, H, D, A, E, I, F, B, C, t Because a topological sort processes vertices in the same manner as a breadth-first search, it tends to produce a more natural ordering.

9.4 The idea is the same as in Exercise 5.10.

9.5 (a) (Unweighted paths) A->B, A->C, A->B->G, A->B->E, A->C->D, A->B->E->F.

(b) (Weighted paths) A->C, A->B, A->B->G, A->B->G->E, A->B->G->E->F, A->B->G-

E->D.

9.6 We’ll assume that Dijkstra’s algorithm is implemented with a priority queue of vertices that uses the DecreaseKey O operation. Dijkstra’s algorithm uses O|O E O|O DecreaseKey O operations, which cost O O(log d OO|O V O|O) each, and O|O V O|O DeleteMin O operations, which cost O O( d Olog d OO|O V O|O) each. The running time is thus O O(O|O E O|Olog d OO|O V O|O + O|O V O|O d Olog d OO|O V O|O). The cost of the DecreaseKey O operations balances the Insert O operations when d O = O|O E O|O / O|O V O|O. For a sparse graph, this might give a value of d O that is less than 2; we can’t allow this, so d O is chosen to be max (2,OIO|O E O|O / O|O V O|OOK). This gives a running time of O O(O|O E O|Olog 2 + O|O E O|O / O|O V O|OO|O V O|O), which is a slight theoretical improvement. Moret and Shapiro report (indirectly) that d O-heaps do not improve the running time in practice.

9.7 (a) The graph shown here is an example. Dijkstra’s algorithm gives a path from A O to C O of cost 2, when the path from A O to B O to C O has cost 1.

A

C

B

(b) We define a pass of the algorithm as follows: Pass 0 consists of marking the start vertex as known and placing its adjacent vertices on the queue. For P j O > 0, pass P j O consists of mark- ing as known all vertices on the queue at the end of pass P j O − 1. Each pass requires linear time, since during a pass, a vertex is placed on the queue at most once. It is easy to show by induction that if there is a shortest path from s O to v O containing k O edges, then dv O will equal the length of this path by the beginning of pass k O. Thus there are at most O|O V O|O passes,

giving an O O(O|O E O|OO|O V O|O) bound.

9.8 See the comments for Exercise 9.19.

9.10 (a) Use an array Count O such that for any vertex u O, Count[u] O is the number of distinct paths from s O to u O known so far. When a vertex v O is marked as known, its adjacency list is traversed. Let w O be a vertex on the adjacency list. If dv O + cv O, w O = dw O, then increment Count[w] O by Count[v] O because all shortest paths from s O to v O with last edge ( v O, w O) give a shortest path to w O. If dv O + cv O, w O < dw O, then pw O and dw O get updated. All previously known shortest paths to w O are now invalid, but all shortest paths to v O now lead to shortest paths for w O, so set Count[w] O to equal Count[v]. O Note: Zero-cost edges mess up this algorithm. (b) Use an array NumEdges O such that for any vertex u O, NumEdges[u] O is the shortest number of edges on a path of distance du O from s O to u O known so far. Thus NumEdges O is used as a tiebreaker when selecting the vertex to mark. As before, v O is the vertex marked known, and w O is adjacent to v O. If dv O + cv O, w O = dw O, then change p (^) w O to v O and NumEdges[w] O to NumEdges[v]+1 O if NumEdges[v]+1 < NumEdges[w]. If dv O + cv O, w O < dw O, then update p (^) w O and dw O, and set NumEdges[w] O to NumEdges[v]+1. O

9.11 (This solution is not unique).

First send four units of flow along the path s, G, H, I, t. This gives the following residual graph:

s

A

D

G

B

E

H

C

F

I

t

Next, send three units of flow along s, D, E, F, t. The residual graph that results is as fol- lows:

s

A

D

G

B

E

H

C

F

I

t

Now two units of flow are sent along the path s, G, D, A, B, C, t, yielding the following residual graph:

9.12 Let T O be the tree with root r O, and children r O 1 , r O 2 , ..., rk O, which are the roots of T O 1 , T O 2 , ..., T (^) k O, which have maximum incoming flow of c O 1 , c O 2 , ..., ck O, respectively. By the problem statement, we may take the maximum incoming flow of r O to be infinity. The recursive function FindMaxFlow( T, IncomingCap ) finds the value of the maximum flow in T O (finding the actual flow is a matter of bookkeeping); the flow is guaranteed not to exceed IncomingCap O. If T O is a leaf, then FindMaxFlow O returns IncomingCap O since we have assumed a sink of infinite capacity. Otherwise, a standard postorder traversal can be used to compute the max- imum flow in linear time.


FlowType FindMaxFlow( Tree T, FlowType IncomingCap ) { FlowType ChildFlow, TotalFlow;

if( IsLeaf( T ) ) return IncomingCap; else { TotalFlow = 0; for( each subtree Ti O of T ) { ChildFlow = FindMaxFlow( Ti O, min( IncomingCap, c (^) i O ) ); TotalFlow += ChildFlow; IncomingCap -= ChildFlow; } return TotalFlow; } }


9.13 (a) Assume that the graph is connected and undirected. If it is not connected, then apply the algorithm to the connected components. Initially, mark all vertices as unknown. Pick any vertex v O, color it red, and perform a depth-first search. When a node is first encountered, color it blue if the DFS has just come from a red node, and red otherwise. If at any point, the depth-first search encounters an edge between two identical colors, then the graph is not bipartite; otherwise, it is. A breadth-first search (that is, using a queue) also works. This problem, which is essentially two-coloring a graph, is clearly solvable in linear time. This contrasts with three-coloring, which is NP-complete. (b) Construct an undirected graph with a vertex for each instructor, a vertex for each course, and an edge between ( v O, w O) if instructor v O is qualified to teach course w O. Such a graph is bipartite; a matching of M O edges means that M O courses can be covered simultaneously. (c) Give each edge in the bipartite graph a weight of 1, and direct the edge from the instruc- tor to the course. Add a vertex s O with edges of weight 1 from s O to all instructor vertices. Add a vertex t O with edges of weight 1 from all course vertices to t O. The maximum flow is equal to the maximum matching.

(d) The running time is O O(O|O E O|OO|O V O|O ⁄

(^1 ) ) because this is the special case of the network flow problem mentioned in the text. All edges have unit cost, and every vertex (except s O and t O) has either an indegree or outdegree of 1.

9.14 This is a slight modification of Dijkstra’s algorithm. Let P f O i O be the best flow from s O to i O at any point in the algorithm. Initially, P f O i O = 0 for all vertices, except s O: P f O s O = ∞. At each stage, we select v O such that P f O v O is maximum among all unknown vertices. Then for each w O adjacent to v O, the cost of the flow to w O using v O as an intermediate is min (P f O v O, cv O, w O). If this value is higher than the current value of P f O w O, then P f O w O and pw O are updated.

9.15 One possible minimum spanning tree is shown here. This solution is not unique.

A B C

D E F G

H I J

9.16 Both work correctly. The proof makes no use of the fact that an edge must be nonnegative.

9.17 The proof of this fact can be found in any good graph theory book. A more general theorem follows: Theorem: Let G O = ( V O, E O) be an undirected, unweighted graph, and let A O be the adjacency matrix for G O (which contains either 1s or 0s). Let D O be the matrix such that D O[ v O][ v O] is equal to the degree of v O; all nondiagonal matrices are 0. Then the number of spanning trees of G O is equal to the determinant of A O + D O.

9.19 The obvious solution using elementary methods is to bucket sort the edge weights in linear time. Then the running time of Kruskal’s algorithm is dominated by the Union/Find O opera- tions and is O O(O|O E O|Oα(O|O E O|O,O|O V O|O)). The Van-Emde Boas priority queues (see Chapter 6 refer- ences) give an immediate O O(O|O E O|OloglogO|O V O|O) running time for Dijkstra’s algorithm, but this isn’t even as good as a Fibonacci heap implementation. More sophisticated priority queue methods that combine these ideas have been proposed, including M. L. Fredman and D. E. Willard, "Trans-dichotomous Algorithms for Minimum Spanning Trees and Shortest Paths," Proceedings of the Thirty-first Annual IEEE Sympo- sium on the Foundations of Computer Science (1990), 719-725. The paper presents a linear-time minimum spanning tree algorithm and an O O(O|O E O|O+O|O V O|O logO|O V O|O / loglogO|O V O|O) implementation of Dijkstra’s algorithm if the edge costs are suitably small.

9.20 Since the minimum spanning tree algorithm works for negative edge costs, an obvious solu- tion is to replace all the edge costs by their negatives and use the minimum spanning tree algorithm. Alternatively, change the logic so that < is replaced by >, Min O by Max O, and vice versa.

9.21 We start the depth-first search at A O and visit adjacent vertices alphabetically. The articula- tion points are C O, E O, and F O. C O is an articulation point because Low O[ B O] ≥ Num O[ C O]; E O is an

9.23 (a) Do a depth-first search and count the number of back edges.

(b) This is the feedback edge set problem. See reference [1] or [20].

9.24 Let ( v O, w O) be a cross edge. Since at the time w O is examined it is already marked, and w O is not a descendent of v O (else it would be a forward edge), processing for w O is already com- plete when processing for v O commences. Thus under the convention that trees (and sub- trees) are placed left to right, the cross edge goes from right to left.

9.25 Suppose the vertices are numbered in preorder and postorder.

If ( v O, w O) is a tree edge, then v O must have a smaller preorder number than w O. It is easy to see that the converse is true. If ( v O, w O) is a cross edge, then v O must have both a larger preorder and postorder number than w O. The converse is shown as follows: because v O has a larger preorder number, w O cannot be a descendent of v O; because it has a larger postorder number, v O cannot be a descendent of w O; thus they must be in different trees. Otherwise, v O has a larger preorder number but is not a cross edge. To test if ( v O, w O) is a back edge, keep a stack of vertices that are active in the depth-first search call (that is, a stack of vertices on the path from the current root). By keeping a bit array indicating presence on the stack, we can easily decide if ( v O, w O) is a back edge or a forward edge.

9.26 The first depth-first spanning tree is

A

B

C

D E

F

G

Gr O, with the order in which to perform the second depth-first search, is shown next. The strongly connected components are {F} and all other vertices.

A,

B,

C,

D,

E,

F,

G,

9.28 This is the algorithm mentioned in the references.

9.29 As an edge ( v O, w O) is implicitly processed, it is placed on a stack. If v O is determined to be an articulation point because Low O[ w O] ≥ Num O[ v O], then the stack is popped until edge ( v O, w O) is removed: The set of popped edges is a biconnected component. An edge ( v O, w O) is not placed on the stack if the edge ( w O, v O) was already processed as a back edge.

9.30 Let ( u O, v O) be an edge of the breadth-first spanning tree. ( u O, v O) are connected, thus they must be in the same tree. Let the root of the tree be r O; if the shortest path from r O to u O is du O, then u O is at level du O; likewise, v O is at level dv O. If ( u O, v O) were a back edge, then du O > dv O, and v O is visited before u O. But if there were an edge between u O and v O, and v O is visited first, then there would be a tree edge ( v O, u O), and not a back edge ( u O, v O). Likewise, if ( u O, v O) were a for- ward edge, then there is some w O, distinct from u O and v O, on the path from u O to v O; this con- tradicts the fact that dv O = dw O + 1. Thus only tree edges and cross edges are possible.

9.31 Perform a depth-first search. The return from each recursive call implies the edge traversal in the opposite direction. The time is clearly linear.

9.33 If there is an Euler circuit, then it consists of entering and exiting nodes; the number of entrances clearly must equal the number of exits. If the graph is not strongly connected, there cannot be a cycle connecting all the vertices. To prove the converse, an algorithm similar in spirit to the undirected version can be used.

9.34 Neither of the proposed algorithms works. For example, as shown, a depth-first search of a biconnected graph that follows A, B, C, D is forced back to A, where it is stranded.

A B

D C

E F

9.35 These are classic graph theory results. Consult any graph theory for a solution to this exer- cise.

9.36 All the algorithms work without modification for multigraphs.