Universitetet i Oslo Institutt for Informatikk S.M. Storleer, S. Kittilsen IN2010: Algoritmer og Datastrukturer Series 2 Tema: Grafteori 1 Publisert: 02. 09. 2019 Utvalgte løsningsforslag Oppgave 1 (Fra boka) R-13.5 Solution Inserting an edges runs in O(1) time since it is simply inserting an element for e = (i, j) into the appropriate two locations, A[i, j] and A[j, i]. To insert a vertex, on the other hand, we must construct a new version of the entire array, A. Clearly this will take O(n 2 ) time. R-13.6 a) b) Solution b: A DF S traversal starting at vertex 1 visits the vertices in the following order: 1, 2, 3, 4, 6, 5, 7, 8. R-13.7 Solution a: The adjacency list structure is preferable. Indeed, the adjacency matrix structure wastes a lot of space. It allocates entries for 100, 000, 000 edges while the graph has only 20, 000 edges. b: In general, both structures work well in this case. Regarding the space requirement, there is no clear winner. Note that the exact space usage of the two structures depends on the implementation details. The adjacency matrix structure is much better for operation areadjacent, while the adjacency list structure is much better for operations insertvertex and removevertex. c: The adjacency matrix structure is preferable. Indeed, it supports operation areadjacent in O(1) time, irrespectively of the number of vertices or edges. C-13.15 Kommentar Løsningsforslaget er basert på DF S algoritmen fra boka s. 367.
Solution Perform a DF S on G. G will have at least two cycles if and only if this DF S encounters at least two back edges. C-13.16 Solution Perform a DF S on G. G will have at least two cycles if and only if this DF S encounters at least two back edges. If there are more than two back edges, then G has more than two cycles. So, for the first back edge, mark all the edges in the cycle determined by this edge and the DF S tree as used. Then, for the second back edge, examine each of the edges in the cycle determined by this edge. If non of them is marked used, then these two cycles are disjoint. If one of them is used, then there are no two disjoint cycles. Oppgave 2 (Eulerkrets) I forelesningen definerte vi en Eulerkrets som en vei som starter og slutter i samme node og er innom alle kantene i G nøyaktig en gang. Vi så på problemet Eulerkrets: Eulerkrets Instans: En graf G Spørsmål: Har G en Eulerkrets? Lag en algoritme som løser Eulerkrets. Output skal være true/false. Kjører algoritmen i polynomiell tid? Begrunn svaret. Hint: Det finnes en egenskap som har med graden til nodene i G å gjøre, som nøyaktig bestemmer om G har en Eulerkrets eller ikke. Løsningsforslag Sjekk om G er sammenhengende. Hvis G inneholder minst to komponenter som inneholder kanter, kan det umulig finnes en Eulerkrets. Sjekk graden til alle nodene i G. Hvis graden til hver eneste node er et partall innholder G en Eulerkrets. Hvis én eller flere noder har odde grad inneholder G ikke en Eulerkrets. Algoritmen bruker polynomiell tid, siden å sjekke om G er sammenhengende kan gjøres med én traversering og fordi det å sjekke graden til hver node kun krever å gå gjennom nabo-lista til hver node. Oppgave 3 (Hamiltonsykel) Vi så også på problemet Hamiltonsykel. Hamiltonsykel Instans: En graf G Spørsmål: Har G en Hamiltonsykel? En Hamiltonsykel i en en graf G er en sykel som inneholder hver node nøyaktig en gang. Lag en algoritme som løser Hamiltonsykel. Output skal være true/false. Hint: Enn så lenge har ingen klart å finne en algoritme som løser dette problemet i polynomiell tid, så ikke ta det så tungt om også din algoritme bruker eksponensiell tid. Løsningsforslag Anta at G har n noder. Generer alle n! permutasjoner av nodene. For hver permutasjon: Sjekk at det går en kant mellom nodene som kommer etter hverandre i permutasjonen Sjekk at det er en kant mellom siste og første node. Oppgave 4 (Dybde-først-søk) I denne oppgaven skal du implementere dybde-først-søk (DFS). Implementer DFS og DFSFull basert på pseudo-koden fra forelesningen. Hvis du ønsker det kan du ta utgangspunkt i koden under. Eksempelgrafen i prekoden er grafen 2
fra slide 19 fra forelesningen. Den riktige traverseringsrekkefølgen etter DFS skal være: 0 1 2 3 4 5 6. Hvorfor gir DFS og DFSFull samme svar for denne grafen? Test koden din på større grafer som ikke er sammenhengende og forklar hvorfor DFS og DFSFull gir forskjellige svar. Løsningsforslag import java.util.list; import java.util.linkedlist; class Node { private int label; private boolean visited = false; private List<Node> neighbors = new LinkedList<Node>(); public Node(int label) { this.label = label; public int getlabel() { return label; public List<Node> getneighbors() { return neighbors; public boolean isvisited() { return visited; public void visit() { visited = true; public void addneighbor(node n) { if (!neighbors.contains(n)) { neighbors.add(n); n.addneighbor(this); public String tostring() { return Integer.toString(label); class Graph { private Node[] nodes; 3
public Graph(Node[] nodes) { this.nodes = nodes; public void printneighbors() { for (Node n1 : nodes) { String s = n1.tostring() + ": "; for (Node n2 : n1.getneighbors()) { s += n2.tostring() + " "; System.out.println(s.substring(0, s.length() - 1)); private static Graph buildexamplegraph() { Node[] nodes = new Node[7]; for (int i = 0; i < 7; i++) { nodes[i] = new Node(i); nodes[0].addneighbor(nodes[1]); nodes[0].addneighbor(nodes[2]); nodes[1].addneighbor(nodes[2]); nodes[2].addneighbor(nodes[3]); nodes[2].addneighbor(nodes[5]); nodes[3].addneighbor(nodes[4]); nodes[4].addneighbor(nodes[5]); nodes[5].addneighbor(nodes[6]); return new Graph(nodes); public void DFS(Node s) { System.out.println(s); s.visit(); for (Node n : s.getneighbors()) { if (n.isvisited() == false) { this.dfs(n); 4
public void DFSFull() { for (Node n : nodes) { if (n.isvisited() == false) { this.dfs(n); public static void main(string[] args) { Graph graph = buildexamplegraph(); graph.printneighbors(); graph.dfsfull(); 5