diff --git a/docs/2a/ece250.md b/docs/2a/ece250.md index dc8875c..9392a1d 100644 --- a/docs/2a/ece250.md +++ b/docs/2a/ece250.md @@ -162,3 +162,119 @@ fn sort(A: Vec) { ### Directed acyclic graphs a DAG is acyclic if and only if there are no **back edges** — edges from a child to an ancestor. + +### Bellman-Ford + +The Bellman-Ford algorithm allows for negative edges and detects negative cycles. + +```rust +fn bf(G: Graph, s: Node) { + let mut distance = Vec::new(INFINITY); + let mut adj_list = Vec::from(G); + + distance[s] = 0; + + for i in 1..G.vertices.len()-1 { + for (u,v) in G.edges { + if distance[v] > distance[u] + adj_list[u][v] { + distance[v] = distance[u] + adj_list[u][v]; + } + } + } + for (u, v) in G.edges { + if distance[v] > distance[u] + adj_list[u][v] { + return false; + } + } + return true; +} +``` + +### Topological sort + +This is used to find the shortest path in a DAG simply by DFS. + +```rust +fn shortest_path(G: Graph, s: Node) { + let nodes: Vec = top_sort(G); + let mut adj_list = G.to_adj_list(); + let mut distance = Vec::new(INFINITY); + + for v in nodes { + for adjacent in adj_list[v] { + if distance[adjacent] > distance[v] + adjacent[v] { + distance[v] = distance[adjacent] + adjacent[v]; + } + } + } +} + +### Minimum spanning tree + +!!! definition + - A **cut** $(S, V-S)$ is a partition of vertices into disjoint sets $S$ and $V-S$. + - An edge $u,v\in E$ **crosses the cut** $(S,V-S)$ if t`he endpoints are on different sides of the cut. + - A cut **respects** a set of edges $A$ if and only if no edge in $A$ crosses the cut. + - A **light edge** is the minimum of all edges that could cross the cut. There can be more than one light edge per cut. + +A **spanning tree** of $G$ is a subgraph that contains all of its vertices. An MST minimises the sum of all edges in the spanning tree. + +To create an MST: + +1. Add edges from the spanning tree to an empty set, maintaining that the set is always a subset of an MST (only "safe edges" are added) + +The **Prim-Jarnik algorithm** grows a tree one vertex at a time. $A$ is a subset of the already computed portion of $T$, and all vertices outside $A$ have a weight of infinity if there is no edge. + +```rust +// r is the start vertex +fn create_mst_prim(G: Graph, r: Vertex) { + // clean all vertices + for vertex in G.vertices.iter_mut() { + vertex.min_weight = INFINITY; + vertex.parent = None; + } + + let Q = BinaryHeap::from(G.vertices); // priority queue + + while let Some(u) = Q.pop() { + for v in u.adjacent_vertices.iter_mut() { + if Q.contains(v) && v.edge_to(u).weight < v.min_weight { + v.min_weight = v.edge_to(u).weight; + Q."modify_key"(v); + v.parent = u; + } + } + } + +} +``` + +**Kruskal's algorithm** is objectively better by relying on edges instead. + +```rust +fn create_mst_kruskal(G: Graph) -> HashSet { + let mut A = HashSet::new(); + let mut S = DisjointSet::new(); // vertices set + + for v in G.vertices.iter() { + S.add_as_new_set(v); + } + G.edges.sort(|edge| edge.weight); + + for (from, dest) in G.edges { + if S.find_set_that_contains(from) != S.find_set_that_contains(dest) { + A.insert((from, to)); + let X = S.pop(from); + let Y = S.pop(to); + S.insert({X.union(Y)}); + } + } + return A; +} +``` + +The time complexity is $O(E\log V)$. + +### All pairs shortest path + +Also known as an adjacency matrix extended such that each point represents the minimum distance from one edge to that other edge.