Answers to Assignment #2 1.(30) See the graph G shown in Fig. 1(a), which can be stored in a file on disk as a set of pairs as shown in Fig. 1(b). Design an algorithm to load the file in main memory and store it as a set of linked lists. (The algorithm should be able to be used for any graph.) (v1, v2) (v1, v3) (v1, v4) (v1, v5) (v2, v3) (v2, v4) (v2, v5) (v3, v4) (v3, v5) (v4, v5) v1 v2 v3 v4 (a) v5 Fig. 1 (b) Each pair represents an edge. Answer: Assume that the graph contains 1000 nodes numbered 1, 2, 3, …, 999. Define a new type Edge with two data fields: class Edge {int id; Edge next) Algorithm graphStorage Edge[] nodes = new Edge[1000];//initially, each node[i] is null. Edge[] points = new Edge[1000];// initially, each node[i] is null. for each pair (x, y) in the file do { z := new Edge(y, null); if points[x] == null then {nodes[x] := z;} else {points[x].next := z; points points[x] := z; 0 } nodes 0 … x … … x … … y 2.(30) Another way to perform topological sorting on a directed acyclic graph G = (V, E) is to repeatedly find a node of in-degree 0, output it, and remove it and all of its outgoing edges from the graph. Explain how to implement this idea so that it runs in time O(|V| + |E|). Answer: Algorithm TopologicalOrder(G) Begin let v1, ..., vk be all the nodes with indegree = 0; for i = 1 to k do {enqueue(Q, vi);} while (Q is not empty) do { v := dequeue(Q); output(v); for (any node u with v u E ) do { indegree(u) := indegree(u) - 1; if indegree(u)= 0 then enqueue(w; } } Assignment #2 3.(40) Consider the graph G shown in Fig. 1(a) once again. Its DFS tree T is shown in Fig. 2(a), in which each node v is associated with (d[v], f[v]). Remember that a node is a descendant of another node v in T if d[v] < d[u]) < f[u] < f[v]). v1 (1, 10) v2 (2, 9) v4 v5 (4, 5) v1 (1, 10) (2, 9) v3 (3, 6) (7, 8) v2 v3 (3, 6)(7, 8) (a) v4 (3, 6) v5 (4, 5) (b) Fig. 2 Describe an algorithm that associates each node v in G with a sequence s of pairs (as shown in Fig. 2(b)) such that u is a descendant of v in G if and only if d[v] < d[u]) < f[u] < f[v]), or there exists a pair p = (a, b) in s with a d[u]) < f[u] b. The working process mainly consists of two steps. In the first step, we will generate the time stamps for all nodes in G. In the second step, we will generate the pair sequence for each node. In the following algorithm, we will use v.d and v.f to refer to the discovery time stamp and the finishing time stamp of v, respectively. We will also use v.L to refer the pair sequence created for v. Algorithm SequenceGeneration (G) Begin Create the time stamp (d[v], f[v]) for each node v by using DFS; find a topological sequence of G: v1, v2, …, vn; For j = n to 1 do { let u1, …, uk be the children of vj; For m = 1 to k do { vj.L := merge(vj.L, um.L); } } end Function merge(L1, L2) Begin i : = 1; j := 1; while (i ≤ |L1| and j ≤ |L2|) do {if L1(i).f < L2(j).d then i := i + 1; If L1(i) L2(j) then j := j + 1; If L2(j).f < L1(i).d then { insert L2(i) into L1 just before L1(j); j := j + 1; } If L2(j) L1(i) then {remove L1(i) from L1; i := i + 1;} } if j ≤ |L2| then put the remaining pairs in L2 at the end of L1; return L1; end Example L1 = [1, 3][6, 9][11, 15] and L2 = [4, 5][7, 8][16, 16]. merge(L1, L2) = [1, 3][4, 5][6, 9][11, 15][16, 16].