Skip to content

Commit c7cd87e

Browse files
Practice Problems from DPV CH3
1 parent 83ad082 commit c7cd87e

13 files changed

Lines changed: 395 additions & 13 deletions

OMSCS/Courses/GA/04.0.1 - Graphs - Black Box Algorithms.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ For the graphs section of this course, you must use the algorithms presented in
177177
- `iter[][]`
178178
- A 2D list containing the first indexed iteration's shortest path from the starting vertex to the second indexed vertex.
179179
- For example, `iter[3][v]` contains the distance from the starting vertex to `v` at the end of the 3rd iteration.
180-
- This stable contains iterations 0 through `n`
180+
- This table contains iterations 0 through `n`
181181

182182
**Runtime:** $O(nm)$
183183

OMSCS/Courses/GA/04.1 - Graphs - SCCs.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,24 @@ How do we get connectivity info for directed G?
4545
## Types of Edges
4646
![[Pasted image 20260227124812.png]]
4747

48-
For a given DFS tree, with pre/postorder numbers, and For a given edge $e=(z,w)$, the edge can have one of the following types.
48+
For a given DFS tree, with pre/postorder numbers, and For a given edge $e=(a,b)$, the edge can have one of the following types.
4949

5050
- tree-edge
5151
- B->A, A->D
52-
- pre(z) < pre(w)
53-
- post(z) > post(w)
52+
- pre(a) < pre(b)
53+
- post(a) > post(b)
5454
- back edge
5555
- E->A, F->B
56-
- pre(z) > pre(w)
57-
- post(z) < post(w)
56+
- pre(a) > pre(b)
57+
- post(a) < post(b)
5858
- forward
5959
- D->G, B->E
60-
- pre(z) < pre(w)
61-
- post(z) > post(w)
60+
- pre(a) < pre(b)
61+
- post(a) > post(b)
6262
- cross
6363
- F->H, H->G
64-
- pre(z) > post(w)
65-
- post(z) > post(w)
64+
- pre(a) > post(a)
65+
- post(a) > post(a)
6666
- There's no situation where the back edge goes the other way. If there's a cross edge pointing the other direction, DFS should have explored that edge and it would actually be a tree-edge.
6767

6868
For back-edges, the post order number goes up. For all other edge types, the post-order number goes down.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
tags:
3+
- OMSCS
4+
- Algorithms
5+
- Practice
6+
- Alg-Graph
7+
---
8+
# 3.1 - DFS on Undirected G
9+
![[Pasted image 20260313091135.png]]
10+
11+
Graph rewritten in mermaid.
12+
13+
```mermaid
14+
graph LR
15+
A --- B
16+
B --- C
17+
C --- F
18+
A --- E
19+
B --- E
20+
E --- F
21+
F --- I
22+
D --- G
23+
G --- H
24+
D --- H
25+
```
26+
27+
Ignore the directed arrows. This graph is meant to be undirected.
28+
29+
| V | Pre | Post |
30+
| --- | --- | ---- |
31+
| A | 1 | 12 |
32+
| B | 2 | 11 |
33+
| C | 3 | 10 |
34+
| D | 13 | 18 |
35+
| E | 5 | 6 |
36+
| F | 4 | 9 |
37+
| G | 14 | 17 |
38+
| H | 15 | 16 |
39+
| I | 7 | 8 |
40+
- **Tree Edges:**
41+
- Tree 1: AB, BC, CF, FE, FI
42+
- Tree 2: DG, GH
43+
- **Back-Edges:**
44+
- Tree 1: EA, EB
45+
- Tree 2: HD
46+
47+
```mermaid
48+
graph TD
49+
50+
A --- B --- C --- F --- I
51+
F --- E
52+
53+
D --- G --- H
54+
55+
E -.- A
56+
E -.- B
57+
H -.- D
58+
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
tags:
3+
- OMSCS
4+
- Algorithms
5+
- Practice
6+
- Alg-Graph
7+
---
8+
# 3.11 - Linear-Time Cycle Detection
9+
> Design a linear-time algorithm which, given an undirected graph G and a particular edge e in it, determines whether G has a cycle containing e.
10+
11+
## Exploration
12+
We know that since this is an undirected graph, given an edge $e=(u,v)$, there will be no $e'=(v,u)$. Therefore, any cycle involving $e$ must also include some vertex $w$ before returning to $v$ or $u$. If we
13+
14+
## Algorithm
15+
Given an edge $e=(u,v)$, remove $e$ from $G$. Run BFS from $u$. If $dist[v] \ne \infty$, then $G$ contains (contained?) a cycle containing edge $e$.
16+
17+
## Justification
18+
If there exists a cycle $C$ in $G=(V,E)$, and $e=(u,v)\in C$, then there are at least 2 paths from $u$ to $v$ in $G$. One of those paths is simply $P=[e]$. Another possible path is $P=C-[e]$. If we remove $e$ from $E$, then the path $P=C-[e]$ may still exist in $G$. If we determine that a path still exists in $G$ from $u$ to $v$ after removing $e$, then adding $e$ back in to $G$ creates a cycle. If $e$ was the only edge connecting 2 disjoint subgraphs, each containing either $u$ or $v$, then there will be no route between the 2 vertices in $G'$.
19+
20+
I used BFS for this because this course overly relies on DFS. You can check if $v$ was reachable from $u$ by checking the distance result. We also could have used DFS for this, using the ccnum result. The ccnum result is valid here, since G is undirected.
21+
22+
## Runtime
23+
- Removing $e$: $O(n)$
24+
- Running BFS from $u$: $O(n+m)$
25+
- Checking `dist[v]`: O(1)
26+
27+
Overall: $O(n+m)$
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
tags:
3+
- OMSCS
4+
- Algorithms
5+
- Practice
6+
---
7+
# 3.2 - DFS on Directed Graphs
8+
![[Pasted image 20260313091325.png]]
9+
10+
## 3.2a
11+
12+
```mermaid
13+
graph
14+
15+
A --> B
16+
A --> F
17+
B --> C
18+
B --> E
19+
C --> D
20+
E --> D
21+
E --> G
22+
D --> B
23+
D --> H
24+
25+
F --> E
26+
F --> G
27+
G --> F
28+
29+
H --> G
30+
```
31+
32+
There is a route directly through the graph which touches all vertices, and the vertices are labeled in such a way that the DFS takes this route every time. Therefore, the pre/post numbers are kind of obvious, especially when you arrange the table by preorder number.
33+
34+
| V | Pre | Post |
35+
| --- | --- | ---- |
36+
| A | 1 | 16 |
37+
| B | 2 | 15 |
38+
| C | 3 | 14 |
39+
| D | 4 | 13 |
40+
| H | 5 | 12 |
41+
| G | 6 | 11 |
42+
| F | 7 | 10 |
43+
| E | 8 | 9 |
44+
45+
Here's the graph again but with Back (B) and Cross (X) edges labelled accordingly. The unlabeled edges are the tree edges.
46+
47+
```mermaid
48+
graph
49+
50+
A --> B
51+
B --> C
52+
53+
C --> D
54+
D --> H
55+
56+
F --> E
57+
G --> F
58+
59+
H --> G
60+
61+
A -.X-.-> F
62+
B -.X-.-> E
63+
64+
D -.B-.-> B
65+
E -.B-.-> D
66+
F -.B-.-> G
67+
E -.B-.-> G
68+
69+
```
70+
## 3.2b
71+
```mermaid
72+
graph
73+
74+
A --> B
75+
A --> H
76+
77+
B --> F
78+
79+
C --> B
80+
81+
D --> C
82+
D --> E
83+
84+
F --> C
85+
F --> D
86+
F --> E
87+
88+
G --> A
89+
G --> B
90+
G --> F
91+
H --> G
92+
```
93+
94+
I did all of these on paper first. This was the first problem where I realized that incrementally building the Pre/Post table along with the Tree/Back/Cross edge lists, was the best way to stay organized. Staying organized means you can do this problem manually in linear time, just like the algorithms.
95+
96+
| V | Pre | Post |
97+
| --- | --- | ---- |
98+
| A | 1 | 16 |
99+
| B | 2 | 11 |
100+
| C | 4 | 5 |
101+
| D | 6 | 9 |
102+
| E | 7 | 8 |
103+
| F | 3 | 10 |
104+
| G | 13 | 14 |
105+
| H | 12 | 15 |
106+
- **Tree Edges:** AB, BF, FC, FD, DE, AH, HG
107+
- **Back Edges:** CB, GA
108+
- **Cross Edges:** DC, FE, GB, GF
109+
110+
```mermaid
111+
graph
112+
113+
A --> B
114+
B --> F
115+
F --> C
116+
F --> D
117+
D --> E
118+
A --> H
119+
H --> G
120+
121+
C -.B-.-> B
122+
G -.B-.-> A
123+
124+
D -.X-.-> C
125+
F -.X-.-> E
126+
G -.X-.-> B
127+
G -.X-.-> F
128+
```
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
---
2+
tags:
3+
- OMSCS
4+
- Algorithms
5+
- Practice
6+
---
7+
# 3.7 - Bipartite Graphs
8+
![[Pasted image 20260313092928.png]]
9+
10+
## 3.7a - Give a Linear-Time Algorithm...
11+
> Give a linear-time algorithm to determine whether an undirected graph is bipartite.
12+
13+
The hint for the solution is the non-sequitur at the beginning of the 3.7b prompt.
14+
15+
> There are many other ways to formulate this property. For instance, an undirected graph is bipartite iff it can be colored with just 2 colors.
16+
17+
If you were to color the natural numbers with only 2 colors, you'd color the even numbers black, and the odd numbers white. We can apply this principle here.
18+
19+
### Algorithm 1 (My Work)
20+
Given an undirected graph, first apply BFS to any arbitrary vertex v in G. Modify the output of BFS, setting the distance from v to v to 0. If there are any vertices which were not reached by the BFS, indicated by an infinite distance from v, continue applying this procedure to arbitrary unreached vertices, merging the distance arrays together at the end. Next, we iterate over all edges in G, and see if it connects a vertex with an even distance to a vertex with an even distance, or a vertex with an odd distance to a vertex with an odd distance. If this is the case, then G is not bipartite. If no such edge is found, then G is bipartite.
21+
22+
This algorithm works because we're using ($dist[v] \mod 2$) as a coloring function. If 2 adjacent vertices have the same "color", then the graph cannot be bipartite.
23+
24+
The issue with this algorithm is the possibility of disconnected graphs. If G consists of $n/5$ uniform bipartite subgraphs of 5 vertices each, then we will need to run BFS $O(n/5)=O(n)$ times. Each of the $n/5$ iterations of BFS needs to perform work linear in the size of $G$. This is because each iteration of BFS must initialize `dist[]` and `prev[]` of length $n$, regardless of the number of vertices which end up being reachable from $s$.
25+
26+
Further, there is an issue at the end of merging $n/5$ `dist[]` arrays, each of length $n$. You can probably avoid this merging operation if you check the coloring in between each execution of BFS. There's likely a way to do this in linear time, effectively you'd need to start by iterating over each edge in $G$ performing the coloring check in an outer loop, and only run BFS when you come across a vertex which has no color.
27+
28+
Regardless, you can't get around the fact that BFS starts with no knowledge of the graph, does not restart when its internal queue is empty, and you can't "bring your own" distance/prev arrays in the black-box implementation as stated in [[04.0.1 - Graphs - Black Box Algorithms]].
29+
30+
31+
### Algorithm 2 (From Classmate)
32+
This solution was inspired by a classmate.
33+
34+
Run DFS on the graph, producing the pre-order and post-order numbers. Iterate over all the edges in G.
35+
36+
From [[04.1 - Graphs - SCCs]], we know that an edge $e=(u,v)$ is a "back edge" if the postorder number of v ($post[v]$) is higher than the postorder number of u ($post[u] < post[v]$). Using this property, we can iterate over the edges in $G$ and check whether it's a back edge or not.
37+
38+
Next, we need to check and see if that backedge forms a cycle of odd length. This occurs when the difference between
39+
40+
If no such edge is found then the graph is bipartite.
41+
42+
> A bipartate graph is one where it can be split into two sets where there is no edge connecting any of the vertices within the same set. To accomplish this, there cannot be a cycle containing an odd number of vertices.
43+
>
44+
> To detect this, our algorithm detects all backedges (an indicator that there is a cycle) and checks the difference in post order numbers. If the difference is even, then we know that there are an add number of vertices within the cycle. So long as no backedges meet this criteria then the graph can be made into a bipartate graph.
45+
46+
See the DFS tree below, with (pre,post) order labelling and backedges noted. Note the backedges, and note how the postorder numbers differ by an even amount on all of these backedges. Any single one of those backedges invalidates $G$ from being bipartite.
47+
48+
```mermaid
49+
graph TD
50+
51+
A["A (1,10)"]
52+
B["B (2,9)"]
53+
C["C (3,6)"]
54+
D["D (7,8)"]
55+
E["E (4,5)"]
56+
57+
A --> B
58+
B --> D
59+
C --> E
60+
B --> C
61+
62+
C -.B-.-> A
63+
D -.B-.-> A
64+
E -.B-.-> B
65+
```
66+
67+
Here's the same graph but with an alternate set of backedges. None of these backedges invalidate G from being bipartite, as they all connect a vertex with an even postorder to a vertex with an odd postorder. Therefore, none of them form an odd cycle.
68+
69+
```mermaid
70+
graph TD
71+
72+
A["A (1,10)"]
73+
B["B (2,9)"]
74+
C["C (3,6)"]
75+
D["D (7,8)"]
76+
E["E (4,5)"]
77+
78+
A --> B
79+
B --> D
80+
C --> E
81+
B --> C
82+
83+
E -.B-.-> C
84+
B -.B-.-> A
85+
C -.B-.-> B
86+
E -.B-.-> A
87+
D -.B-.-> B
88+
```
89+
90+
### Algorithm 2 (From TA)
91+
We can convert this problem to a 2-SAT problem. See [[04.2 - Graphs - 2-SAT]] for details on that algorithm. To encode this problem as a 2-SAT problem, we need to define the problem in terms of the conjunctive AND of multiple OR clauses, each with 2 literals. How do we do this?
92+
93+
In a bipartite graph, all edges must connect one vertex $v \in S_1$ with a vertex in $u \in S_2$. $V = S_1 \cup S_2$ and $S_1 \cap S_2=\emptyset$. Therefore, we need to model vertex $v$ as being in one set or the other set, and vertex $u$ as being in the opposite set. This can be accomplished as an exclusive-or (XOR).
94+
95+
- The variable $v_i$ indicates the question "Is $v_i \in S_1$?".
96+
- The literal $v_i$ indicates the answer "$v_i \in S_1$" and simultaneously "$v_i \notin S_2$"
97+
- The literal $\overline{v_i}$ indicates the answer "$v_i \notin S_1$" and simultaneously "$v_i \in S_2$"
98+
99+
For each edge $e=(v_a, v_b) \in E$, we know that $G$ must be bipartite if:
100+
$$\big(v_a \wedge \overline{v_b}\big) \vee \big(\overline{v_a} \wedge v_b\big)$$
101+
102+
We can reframe this XOR condition in CNF thusly:
103+
$$\big(v_a \vee v_b\big) \wedge \big(\overline{v_a} \vee \overline{v_b}\big) $$
104+
105+
Taking the AND across all of these CNF-XOR conditions produces a 2-SAT problem. The conversion from $G$ to $f$ takes $O(n+m)$ time. The 2-SAT algorithm takes $O(n+m)$ time.
106+
107+
## 3.7b - Odd Cycles
108+
We can't have an odd-length cycle in a bipartite graph, because each edge must connect a vertex $v \in S_1$ with a vertex in $u \in S_2$, where $V = S_1 \cup S_2$ and $S_1 \cap S_2=\emptyset$.
109+
110+
Let's assume that $G$ is a bipartite graph containing an $L$-length cycle, where $L$ is odd. Let's pick some vertex $a$ which is in $S_1$, and is part of the odd-length cycle. If we traverse around the cycle, we reach a vertex in $S_2$, then a vertex in $S_1$, then a vertex in $S_2$. After all even numbered steps, we've reached a vertex in $S_1$. After all odd numbered steps, we've reached a vertex in $S_2$. After $L$ steps, which is an odd number of steps, we've reached vertex $a$, which must be in $S_2$. This presents a contradiction. $a$ must be in both $S_1$ and $S_2$, but the intersection of $S_1$ and $S_2$ is the empty set. Therefore, our initial assumption that $G$ is bipartite is incorrect.
111+
112+
## 3.7c - Coloring Odd-Length Cycles
113+
You need 3 colors. As you traverse around the cycle, you must give each vertex an alternating color. At the end, you will have 2 adjacent vertices which have the same color. You'll need to change one of them to some third color. QED.

0 commit comments

Comments
 (0)