cpsc 490 problem solving in computer science
play

CPSC 490: Problem Solving in Computer Science Assignment 1 is due - PowerPoint PPT Presentation

Lecture 2: Graph Traversals, Shortest Paths Henry Xia, Brandon Zhang based on CPSC 490 slides from 2014-2018 2019-01-08 University of British Columbia CPSC 490: Problem Solving in Computer Science Assignment 1 is due Jan 15 at noon.


  1. Lecture 2: Graph Traversals, Shortest Paths Henry Xia, Brandon Zhang based on CPSC 490 slides from 2014-2018 2019-01-08 University of British Columbia CPSC 490: Problem Solving in Computer Science

  2. • Assignment 1 is due Jan 15 at noon. • Announcements and assignment hints will be posted on Piazza. • If you don’t have a judge account or forgot your password, make a private post on Piazza. • Offjce hours this week: Mon, Wed, Thu 2-3 pm, Fri 1-2 pm in ICICS 005. 1 Announcements • Sign up for Piazza! http://piazza.com/ubc.ca/winterterm22018/cpsc490

  3. • Represent relationships with nodes (vertices) and edges. • Notation: Call the set of nodes V , and the set of edges E . • Each edge connects some pair of nodes, edges can be • Bidirectional (undirected) • One-directional (directed) • Weighted • A tree is a connected graph with no cycles. 2 What are graphs? Figure 1: An undirected graph (Source: Wikipedia)

  4. Tons of problems we can solve in terms of graphs! • Shortest path problems • Dependency/connectivity problems • Cycle detection • Minimum cost substructures (trees, matchings, etc.) • and many many more... 3 Why study graphs? Figure 2: Shortest path problems have a natural representation in graphs.

  5. • adj[u][v] is true if there is an edge u Adjacency list • Advantages: memory effjcient, easy & fast to iterate through neighbours • Can use a set instead of a list, but slower Adjacency matrix v • Advantages: good for dense graphs, easy to test if u v is an edge • Disadvantages: slow to find neighbours, not effjcient for sparse graphs An undirected edge u v is represented as two directed edges u v , v u . In almost all problems, adjacency lists are the best representation to use. 4 Graph representations • adj[u] is a list of neighbours of u • Disadvantages: slow to check if ( u , v ) is an edge

  6. Adjacency list • Advantages: memory effjcient, easy & fast to iterate through neighbours • Can use a set instead of a list, but slower Adjacency matrix • Disadvantages: slow to find neighbours, not effjcient for sparse graphs An undirected edge u v is represented as two directed edges u v , v u . In almost all problems, adjacency lists are the best representation to use. 4 Graph representations • adj[u] is a list of neighbours of u • Disadvantages: slow to check if ( u , v ) is an edge • adj[u][v] is true if there is an edge u → v • Advantages: good for dense graphs, easy to test if ( u , v ) is an edge

  7. Adjacency list • Advantages: memory effjcient, easy & fast to iterate through neighbours • Can use a set instead of a list, but slower Adjacency matrix • Disadvantages: slow to find neighbours, not effjcient for sparse graphs In almost all problems, adjacency lists are the best representation to use. 4 Graph representations • adj[u] is a list of neighbours of u • Disadvantages: slow to check if ( u , v ) is an edge • adj[u][v] is true if there is an edge u → v • Advantages: good for dense graphs, easy to test if ( u , v ) is an edge An undirected edge ( u , v ) is represented as two directed edges u → v , v → u .

  8. Adjacency list • Advantages: memory effjcient, easy & fast to iterate through neighbours • Can use a set instead of a list, but slower Adjacency matrix • Disadvantages: slow to find neighbours, not effjcient for sparse graphs In almost all problems, adjacency lists are the best representation to use. 4 Graph representations • adj[u] is a list of neighbours of u • Disadvantages: slow to check if ( u , v ) is an edge • adj[u][v] is true if there is an edge u → v • Advantages: good for dense graphs, easy to test if ( u , v ) is an edge An undirected edge ( u , v ) is represented as two directed edges u → v , v → u .

  9. a b a b 5 Problem 1 – Connectivity Input : a graph with N nodes and M edges. Output : true if node a and node b are connected, false otherwise.

  10. def connected(a, b): if a == b: return True for v in neighbours of a: if connected(v, b): return True return False 6 • might never terminate if the graph has a cycle. • too slow! It checks the same node multiple times. What’s wrong with this? 7 6 4 5 3 2 1 This suggests a recursive solution! connected. Problem 1 – Solution Attempt a and b are connected ⇐ ⇒ a = b , or there is a neighbour v of a such that v and b are

  11. 6 3 • might never terminate if the graph has a cycle. • too slow! It checks the same node multiple times. What’s wrong with this? 7 6 5 4 1 2 This suggests a recursive solution! connected. Problem 1 – Solution Attempt a and b are connected ⇐ ⇒ a = b , or there is a neighbour v of a such that v and b are def connected(a, b): if a == b: return True for v in neighbours of a: if connected(v, b): return True return False

  12. 6 3 • might never terminate if the graph has a cycle. • too slow! It checks the same node multiple times. What’s wrong with this? 7 6 5 4 1 2 This suggests a recursive solution! connected. Problem 1 – Solution Attempt a and b are connected ⇐ ⇒ a = b , or there is a neighbour v of a such that v and b are def connected(a, b): if a == b: return True for v in neighbours of a: if connected(v, b): return True return False

  13. 6 3 • might never terminate if the graph has a cycle. • too slow! It checks the same node multiple times. What’s wrong with this? 7 6 5 4 1 2 This suggests a recursive solution! connected. Problem 1 – Solution Attempt a and b are connected ⇐ ⇒ a = b , or there is a neighbour v of a such that v and b are def connected(a, b): if a == b: return True for v in neighbours of a: if connected(v, b): return True return False

  14. This is depth-first-search (DFS). However, this implementation might cause a stack 7 8 overflow due to the recursive calls. 2 3 This is better! We only process each node at most once. 4 10 5 9 6 1 7 Problem 1 – Solution Attempt 2 def connected(a, b): if a == b: return True if a is visited: return False mark a as visited for v in neighbours of a: if connected(v, b): return True return False

  15. 7 6 overflow due to the recursive calls. However, this implementation might cause a stack This is depth-first-search (DFS). This is better! We only process each node at most once. 10 9 8 1 7 4 5 3 2 Problem 1 – Solution Attempt 2 def connected(a, b): if a == b: return True if a is visited: return False mark a as visited for v in neighbours of a: if connected(v, b): return True return False

  16. 7 8 overflow due to the recursive calls. 2 This is depth-first-search (DFS). However, this implementation might cause a stack 3 This is better! We only process each node at most once. 4 10 5 9 6 1 7 Problem 1 – Solution Attempt 2 def connected(a, b): if a == b: return True if a is visited: return False mark a as visited for v in neighbours of a: if connected(v, b): return True return False

  17. 8 6 We simulate the call stack with an actual stack. 12 11 10 9 8 1 7 3 2 4 5 Problem 1 – Solution Attempt 3 def connected(a, b): s = new stack containing a while s is not empty: u = pop(s) if u == b: return True if u is visited: continue mark u as visited for v in neighbours of u: push(s, v) return False

  18. Graph traversal algorithm which starts at a given node, explores as deep as possible, and backtracks when it hits a dead end. Things to consider for a DFS problem: • What needs to be done when ... • visiting a new node? • backtracking? • visiting an already visited node? • visiting the target node? • Do you need “shortest path”? If so, DFS is not the answer! 9 Depth-first search (DFS) • Time complexity: O ( | V | + | E | )

  19. What happens when we replace the stack in DFS with a queue? distance from the source before moving on. 10 Breadth-first search (BFS) Obtain breadth-first search: explores nodes “level by level”, visiting all nodes at a certain • Time complexity: O ( | V | + | E | )

  20. S 1 1 2 3 2 3 4 11 Problem 2 – Shortest path, unweighted Input : a connected graph with N nodes and M edges, and a source node S . Output : for each v ∈ V , the distance from v to S .

  21. 12 5 Try implementing it without a visited array! 10 9 8 7 Run BFS! 6 4 3 2 1 Problem 2 – Solution q = new queue containing (S, 0) while q is not empty: (u, cost) = dequeue(q) if u is visited: continue mark u as visited dist[u] = cost for v in neighbours of u: enqueue(q, (v, cost + 1)) return dist

  22. 12 5 Try implementing it without a visited array! 10 9 8 7 Run BFS! 6 4 3 2 1 Problem 2 – Solution q = new queue containing (S, 0) while q is not empty: (u, cost) = dequeue(q) if u is visited: continue mark u as visited dist[u] = cost for v in neighbours of u: enqueue(q, (v, cost + 1)) return dist

  23. 13 Problem 3 – Grid Maze Input : a rectangular grid maze with obstacles, an entrance, and an exit. Output : the length of the shortest path between the entrance and exit. S . . . . . . X . . X . . . X . . E Figure: An example of a grid maze

  24. 14 Run BFS! Problem 3 – Solution

  25. 15 Problem 4 – Grid Maze (Modified) Input : a rectangular grid maze with obstacles, an entrance, and an exit. Output : the cells in the grid which are not on any shortest path from entrance to exit. S . . . . . o X . . X . o o X . . E Figure: The same grid maze, with o marking cells not on any shortest path.

Recommend


More recommend