homework.wenqian.dev
← Back to index
Homework 22026-08-13

Graph, Stack, Queue, Search

Build a graph · Use a stack · Use a queue · Then write BFS and DFS yourself

Requirements

  • 6 required problems. Estimated time: 2 – 3 hours.
  • Submit one Python file (.py) per problem.
  • The problems go in order. 1 is the graph, 2 is the stack, 3 is the queue, and 4–6 put them together. Do them in order.
  • Use a plain list as your stack and queue. Only append(), pop() and pop(0). Do not import deque or any other module.
  • Never visit a node twice. Every search must keep a record of what it has already seen.
  • Output format must match the samples exactly, including spaces.

The graph used in problems 1, 5 and 6

plain
    A ------- B ------- C    |         |         |    |         |         |    D ------- E         F              |              G

Draw this on paper before you start. Almost every mistake in this homework is a drawing mistake, not a Python mistake.

Problems

1Neighbour List

Read a graph and store it as a dict: every node name maps to a list of its neighbours. Then print the neighbours of one node, in alphabetical order.

Remember that an edge is undirected. The line A B means B is a neighbour of A and A is a neighbour of B.

Input format

text
First line: two integers n and m — how many nodes and how many edges.Second line: n node names.Next m lines: two node names, meaning an edge between them.Every edge works in BOTH directions.Constraint: 1 ≤ n ≤ 50Last line: one node name q.

Output format

text
One line: the neighbours of q in alphabetical order, separated by single spaces.If q has no neighbours, print none

Sample 1

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GB

Output

text
A C E

Sample 2

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GF

Output

text
C

Sample 3

Input

text
3 1A B CA BC

Output

text
none

Required structure

neighbour_list.py
def build_graph(names, edges):    # TODO: start every name with an empty list,    #       then add BOTH directions for every edge    passdef neighbours_of(graph, node):    # TODO: return the neighbour list, sorted    passfirst = input().split()n = int(first[0])m = int(first[1])names = input().split()edges = []for _ in range(m):    parts = input().split()    edges.append((parts[0], parts[1]))q = input().strip()graph = build_graph(names, edges)result = neighbours_of(graph, q)if len(result) == 0:    print("none")else:    print(" ".join(result))
Hint: Give every name an empty list first, so a node with no edges still exists as a key. For each edge, run append twice — once on each side.
2Undo Log

A drawing program keeps a log of what you did. Every undo removes the most recent action. That makes the log a stack.

Input format

text
First line: one integer k — how many commands.Next k lines: either    do WORD     record one action    undo        remove the most recent actionConstraint: 1 ≤ k ≤ 100

Output format

text
For every undo, print the action that was removed.If the log was already empty, print nothingAfter all commands, print the remaining log on one line, oldest first.If the log is empty at the end, print empty

Sample 1

Input

text
5do drawdo eraseundodo fillundo

Output

text
erasefilldraw

Sample 2

Input

text
2undoundo

Output

text
nothingnothingempty

Sample 3

Input

text
4do ado bdo cundo

Output

text
ca b

Required structure

undo_log.py
k = int(input())log = []for _ in range(k):    parts = input().split()    if parts[0] == "do":        # TODO: record parts[1]        pass    else:        # TODO: remove and print the most recent action,        #       or print nothing when the log is empty        pass# TODO: print the remaining log, or empty
Hint: log.pop() takes the most recent action. Always check len(log) == 0 first — popping an empty list crashes.
3Ticket Line

People join the back of a line and are served from the front. Same problem shape as number 2, opposite rule. Compare your two files afterwards — only one thing changed.

Input format

text
First line: one integer k — how many commands.Next k lines: either    join NAME   the person joins the back of the line    serve       the person at the front is servedConstraint: 1 ≤ k ≤ 100

Output format

text
For every serve, print the name of the person served.If the line was empty, print nobodyAfter all commands, print who is still waiting on one line, front first.If nobody is waiting, print empty

Sample 1

Input

text
6join anajoin boservejoin cyserveserve

Output

text
anabocyempty

Sample 2

Input

text
4join anajoin boservejoin cy

Output

text
anabo cy

Sample 3

Input

text
2serveserve

Output

text
nobodynobodyempty

Required structure

ticket_line.py
k = int(input())line = []for _ in range(k):    parts = input().split()    if parts[0] == "join":        # TODO: parts[1] joins the BACK        pass    else:        # TODO: serve and print the person at the FRONT,        #       or print nobody when the line is empty        pass# TODO: print who is still waiting, or empty
Hint: Joining is still append(). Only the taking changes: pop(0) instead of pop().
4Two Rules, One Function

Put the same values into a waiting list, then empty it twice: once as a queue, once as a stack. Write one function that does both, with a mode parameter.

Input format

text
First line: one integer n.Second line: n values separated by spaces.Constraint: 1 ≤ n ≤ 100

Output format

text
Two lines.Line 1: the values taken out using a QUEUE, separated by single spaces.Line 2: the values taken out using a STACK.

Sample 1

Input

text
41 2 3 4

Output

text
1 2 3 44 3 2 1

Sample 2

Input

text
17

Output

text
77

Sample 3

Input

text
510 20 30 40 50

Output

text
10 20 30 40 5050 40 30 20 10

Required structure

two_rules.py
def take_all(items, mode):    # TODO: copy every item into a waiting list,    #       then empty it. "queue" takes the front,    #       "stack" takes the back.    passn = int(input())values = input().split()print(" ".join(take_all(values, "queue")))print(" ".join(take_all(values, "stack")))
Hint: Do not write the function twice. Everything above the while loop is identical — only the line that removes an item depends on mode.
5Fewest Steps

Given a graph, a start node and a goal node, print the smallest number of edges you have to walk to get from the start to the goal.

You must use a queue. A stack would still find a route, but not always the shortest one.

Input format

text
First line: two integers n and m — how many nodes and how many edges.Second line: n node names.Next m lines: two node names, meaning an edge between them.Every edge works in BOTH directions.Constraint: 1 ≤ n ≤ 50Last line: two node names, the start and the goal.

Output format

text
One line: the number of edges on the shortest route.Print 0 when the start is the goal.Print -1 when there is no route at all.

Sample 1

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GA F

Output

text
3

Sample 2

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GA G

Output

text
3

Sample 3

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GA A

Output

text
0

Sample 4

Input

text
4 2A B C DA BC DA D

Output

text
-1

Required structure

fewest_steps.py
def build_graph(names, edges):    # TODO: same as problem 1    passdef fewest_steps(graph, start, goal):    frontier = [start]    steps = {start: 0}      # this dict is also the "already seen" record    while len(frontier) > 0:        # TODO: take the OLDEST cell out of frontier        # TODO: if it is the goal, return steps[current]        # TODO: for every unseen neighbour,        #       steps[nxt] = steps[current] + 1, then add it to frontier        pass    return -1first = input().split()n = int(first[0])m = int(first[1])names = input().split()edges = []for _ in range(m):    parts = input().split()    edges.append((parts[0], parts[1]))last = input().split()graph = build_graph(names, edges)print(fewest_steps(graph, last[0], last[1]))
Hint: steps does two jobs at once, exactly like came_fromin class: it stores the distance, and being a key means "already seen". Sample 4 has two separate pieces, so the queue empties without ever reaching D.
6Two Orders

Print the order in which the nodes are visited, first using a queue (BFS), then using a stack (DFS). Write one function with a mode parameter, just like problem 4.

Tie-break rule: when you add the neighbours of a node, always add them in alphabetical order. Without this rule the answer would not be unique.

Input format

text
First line: two integers n and m — how many nodes and how many edges.Second line: n node names.Next m lines: two node names, meaning an edge between them.Every edge works in BOTH directions.Constraint: 1 ≤ n ≤ 50Last line: one node name, the start.

Output format

text
Two lines.Line 1: the BFS visit order, separated by single spaces.Line 2: the DFS visit order.Only nodes you can actually reach appear.

Sample 1

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GA

Output

text
A B D C E F GA D E G B C F

Sample 2

Input

text
7 7A B C D E F GA BB CA DB EC FD EE GF

Output

text
F C B A E D GF C B E G D A

Sample 3

Input

text
4 3A B C DA BA CB DA

Output

text
A B C DA C B D

Required structure

two_orders.py
def build_graph(names, edges):    # TODO: same as problem 1, but sort every    #       neighbour list before you return    passdef visit_order(graph, start, mode):    frontier = [start]    seen = {start: True}    order = []    while len(frontier) > 0:        # TODO: "bfs" takes the oldest, "dfs" takes the newest        # TODO: add current to order        # TODO: add every unseen neighbour to seen and to frontier        pass    return orderfirst = input().split()n = int(first[0])m = int(first[1])names = input().split()edges = []for _ in range(m):    parts = input().split()    edges.append((parts[0], parts[1]))start = input().strip()graph = build_graph(names, edges)print(" ".join(visit_order(graph, start, "bfs")))print(" ".join(visit_order(graph, start, "dfs")))
Hint: Mark a node as seen the moment you add it to the frontier, not when you take it out. Marking it late lets the same node enter the frontier twice. Check sample 1 by hand on your drawing before you run it.
Check: Problems 4 and 6 must each contain exactly one search function. If you wrote two nearly identical functions, delete one and add the mode parameter instead — that single line is the whole point of this week.
— Homework 2 End —