├── .gitignore ├── 02-Graph-Basics ├── 03-Adjacency-Matrix │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ └── main.rs ├── 04-Other-Methods-in-Graph │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ └── main.rs ├── 06-Adjacency-List │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── adjlist.rs │ │ ├── adjmatrix.rs │ │ └── main.rs ├── 08-Adjacency-Set │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── adjlist.rs │ │ ├── adjmatrix.rs │ │ ├── adjset.rs │ │ └── main.rs ├── 09-Graph-Representation-Comparation │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs └── README.md ├── 03-Graph-DFS ├── 04-Graph-DFS-Implementation │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 05-Graph-DFS-Improvement │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs └── README.md ├── 04-Graph-DFS-Applications ├── 01-Connected-Components-Count │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 02-Connected-Components │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 03-More-about-Connected-Components │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 05-Single-Source-Path │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 08-Path-Improvement │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs ├── 09-Cycle-Detection │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── graph.rs │ │ └── main.rs └── 11-Bipartition-Detection │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ ├── g3.txt │ └── src │ ├── graph.rs │ └── main.rs ├── 05-Graph-BFS ├── 02-BFS │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── graph.rs │ │ ├── graph_bfs.rs │ │ └── main.rs ├── 03-Single-Source-Path-BFS │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g1.txt │ └── src │ │ ├── graph.rs │ │ ├── graph_bfs.rs │ │ └── main.rs └── 09-Unweighted-Shortest-Path │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g1.txt │ └── src │ ├── graph.rs │ ├── graph_bfs.rs │ ├── main.rs │ └── unweighted_shortest_path.rs ├── 06-Graph-Modelling-and-Floodfill ├── 01-Leetcode-Graph-Basics │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 03-Graph-Construction │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── solution.rs ├── 04-Flood-Fill │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── solution.rs │ │ └── solution2.rs └── README.md ├── 07-AI-Search-and-BFS ├── 01-Leetcode-BFS │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 03-States │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 04-Water-Puzzle-Uncompleted │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 05-Water-Puzzle-Completed │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 06-Sliding-Puzzle-Uncompleted │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs └── 07-Sliding-Puzzle-Completed │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ └── main.rs ├── 08-Bridges-and-Cut-Points ├── 04-Bridges-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ ├── g3.txt │ ├── src │ │ ├── edge.rs │ │ ├── find_bridges.rs │ │ ├── graph.rs │ │ └── main.rs │ └── tree.txt └── 07-Cut-Points-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ ├── g3.txt │ ├── src │ ├── edge.rs │ ├── find_bridges.rs │ ├── find_cut_points.rs │ ├── graph.rs │ └── main.rs │ └── tree.txt ├── 09-Hamilton-Loop-and-Path ├── 03-Hamilton-Loop │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── graph.rs │ │ ├── hamilton_loop.rs │ │ └── main.rs ├── 04-Hamilton-Loop-Optimization │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── graph.rs │ │ ├── hamilton_loop.rs │ │ └── main.rs ├── 06-Unique-Paths-III │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── 08-State-Compression │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs └── 09-Memory-Search │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ └── main.rs ├── 10-Euler-Loop-and-Euler-Path ├── 03-Euler-Loop-Detection │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── euler_loop.rs │ │ ├── graph.rs │ │ └── main.rs └── 06-Hierholzer-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ ├── euler_loop.rs │ ├── graph.rs │ └── main.rs ├── 11-Minimum-Tree-Spanning ├── 01-Weighted-Graph │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── weighted_graph.rs ├── 02-Weighted-Graph-Completed │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── main.rs │ │ └── weighted_graph.rs ├── 05-Kruskal-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── cc.rs │ │ ├── kruskal.rs │ │ ├── main.rs │ │ ├── union_find.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs ├── 06-Kruskal-Algorithm-Completed │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── cc.rs │ │ ├── kruskal.rs │ │ ├── main.rs │ │ ├── union_find.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs ├── 08-Prim-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── cc.rs │ │ ├── main.rs │ │ ├── prim.rs │ │ ├── union_find.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs └── 09-Prim-Algorithm-Optimized │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ ├── cc.rs │ ├── main.rs │ ├── prim.rs │ ├── weighted_edge.rs │ └── weighted_graph.rs ├── 12-Shortest-Path ├── 03-Dijkstra-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── dijkstra.rs │ │ ├── main.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs ├── 04-Dijkstra-Algorithm-Optimized │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ └── src │ │ ├── dijkstra.rs │ │ ├── main.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs ├── 08-Bellman-Ford-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── bellman_ford.rs │ │ ├── dijkstra.rs │ │ ├── main.rs │ │ ├── weighted_edge.rs │ │ └── weighted_graph.rs └── 11-Floyed-Algorithm │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ ├── bellman_ford.rs │ ├── dijkstra.rs │ ├── floyed.rs │ ├── main.rs │ ├── weighted_edge.rs │ └── weighted_graph.rs ├── 13-Directed-Graph ├── 01-Directed-Graph │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── graph.rs │ │ ├── main.rs │ │ └── weighted_graph.rs │ ├── ug.txt │ └── wg.txt ├── 03-Directed-Cycle-Detection │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── directed_cycle_detection.rs │ │ ├── graph.rs │ │ └── main.rs │ ├── ug.txt │ ├── ug2.txt │ └── wg.txt ├── 04-Directed-Graph-Degrees │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── graph.rs │ │ └── main.rs │ ├── ug.txt │ ├── ug2.txt │ └── wg.txt ├── 05-Directed-Euler-Loop │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── euler_loop.rs │ │ ├── graph.rs │ │ └── main.rs │ ├── ug.txt │ └── ug2.txt ├── 07-Topological-Sort │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── graph.rs │ │ ├── main.rs │ │ └── topo_sort.rs │ └── ug.txt └── 12-SCC │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ ├── dfs.rs │ ├── graph.rs │ ├── main.rs │ └── scc.rs │ └── ug.txt ├── 14-Network-Flows └── 06-Edmonds-Karp-Algorithm-Completed │ ├── Cargo.lock │ ├── Cargo.toml │ ├── network.txt │ ├── network2.txt │ └── src │ ├── main.rs │ ├── max_flow.rs │ └── weighted_graph.rs ├── 15-Matching-Algorithm ├── 03-Solving-Matching-Problem-in-Max-Flow │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── bipartition.rs │ │ ├── bipatite_matching.rs │ │ ├── graph.rs │ │ ├── main.rs │ │ ├── max_flow.rs │ │ └── weighted_graph.rs ├── 06-Hungarian-BFS │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ │ ├── bipartition.rs │ │ ├── graph.rs │ │ ├── hungarian.rs │ │ ├── main.rs │ │ ├── max_flow.rs │ │ └── weighted_graph.rs └── 07-Hungarian-DFS │ ├── Cargo.lock │ ├── Cargo.toml │ ├── g.txt │ ├── g2.txt │ └── src │ ├── bipartition.rs │ ├── graph.rs │ ├── hungarian.rs │ ├── main.rs │ ├── max_flow.rs │ └── weighted_graph.rs ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ###################### 2 | # OS generated files # 3 | ###################### 4 | .DS_Store 5 | .DS_Store? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | ehthumbs.db 10 | Thumbs.db 11 | 12 | ##################### 13 | # Rust Ignore files # 14 | ##################### 15 | target/ 16 | .idea/ 17 | -------------------------------------------------------------------------------- /02-Graph-Basics/03-Adjacency-Matrix/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter2-p3" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /02-Graph-Basics/03-Adjacency-Matrix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter2-p3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/03-Adjacency-Matrix/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /02-Graph-Basics/03-Adjacency-Matrix/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | use std::fs; 3 | 4 | #[derive(Debug)] 5 | struct AdjMatrix { 6 | v: i32, 7 | e: i32, 8 | adj: Vec>, 9 | } 10 | 11 | impl AdjMatrix { 12 | pub fn from(filename: &str) -> Self { 13 | let file = fs::read_to_string(filename).unwrap(); 14 | let mut iter = file.split("\n").into_iter(); 15 | let mut first_line = iter.next().unwrap().split_whitespace(); 16 | let v = first_line.next().unwrap().parse::().unwrap(); 17 | let e = first_line.next().unwrap().parse::().unwrap(); 18 | let mut ret = AdjMatrix { 19 | v, 20 | e, 21 | adj: vec![vec![0; v as usize]; v as usize], 22 | }; 23 | while let Some(line) = iter.next() { 24 | if line.len() == 0 { 25 | break; 26 | } 27 | let mut line = line.split_whitespace(); 28 | let x = line.next().unwrap().parse::().unwrap(); 29 | let y = line.next().unwrap().parse::().unwrap(); 30 | ret.mut_adj()[x][y] = 1; 31 | ret.mut_adj()[y][x] = 1; 32 | } 33 | 34 | return ret; 35 | } 36 | 37 | pub fn mut_adj(&mut self) -> &mut Vec> { 38 | &mut self.adj 39 | } 40 | } 41 | 42 | impl Display for AdjMatrix { 43 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 44 | let mut matrix = String::new(); 45 | for line in &self.adj { 46 | for num in line { 47 | matrix.push_str(num.to_string().as_str()); 48 | matrix.push_str(" "); 49 | } 50 | matrix.pop(); 51 | matrix.push_str("\n"); 52 | } 53 | write!( 54 | f, 55 | "AdjMatrix: \nV: {}, \nE: {}, \nMatrix: \n{}", 56 | self.v, self.e, matrix 57 | ) 58 | } 59 | } 60 | 61 | pub fn main() { 62 | let adj = AdjMatrix::from("g.txt"); 63 | println!("{}", adj); 64 | } 65 | -------------------------------------------------------------------------------- /02-Graph-Basics/04-Other-Methods-in-Graph/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter2-p3" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /02-Graph-Basics/04-Other-Methods-in-Graph/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter2-p3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/04-Other-Methods-in-Graph/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /02-Graph-Basics/06-Adjacency-List/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter2-p6" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /02-Graph-Basics/06-Adjacency-List/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter2-p6" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/06-Adjacency-List/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /02-Graph-Basics/06-Adjacency-List/src/adjlist.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::collections::LinkedList; 3 | use std::fmt::{Display, Formatter}; 4 | use std::fs; 5 | 6 | #[derive(Debug)] 7 | pub struct AdjList { 8 | v: usize, 9 | e: usize, 10 | adj: Vec>, 11 | } 12 | 13 | impl AdjList { 14 | pub fn from(filename: &str) -> Self { 15 | let file = fs::read_to_string(filename).unwrap(); 16 | let mut iter = file.split("\n").into_iter(); 17 | let mut first_line = iter.next().unwrap().split_whitespace(); 18 | 19 | let v = first_line.next().unwrap().parse::().unwrap(); 20 | let e = first_line.next().unwrap().parse::().unwrap(); 21 | 22 | let mut ret = AdjList { 23 | v, 24 | e, 25 | adj: vec![LinkedList::new(); v as usize], 26 | }; 27 | 28 | while let Some(line) = iter.next() { 29 | if line.len() == 0 { 30 | break; 31 | } 32 | let mut line = line.split_whitespace(); 33 | let x = line.next().unwrap().parse::().unwrap(); 34 | let y = line.next().unwrap().parse::().unwrap(); 35 | ret.validate_vertex(x); 36 | ret.validate_vertex(y); 37 | 38 | if x == y { 39 | panic!("Self Loop is Detected!"); 40 | } 41 | if ret.adj[x].contains(&y) { 42 | panic!("Parallel Edges are Detected!"); 43 | } 44 | 45 | ret.adj[x].push_back(y); 46 | ret.adj[y].push_back(x); 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | pub fn e(&self) -> usize { 53 | self.e 54 | } 55 | 56 | pub fn v(&self) -> usize { 57 | self.v 58 | } 59 | 60 | pub fn has_edge(&self, v1: usize, v2: usize) -> bool { 61 | self.validate_vertex(v1); 62 | self.validate_vertex(v2); 63 | return self.adj[v1].contains(&v2); 64 | } 65 | 66 | fn validate_vertex(&self, v: usize) { 67 | if v >= self.v as usize { 68 | panic!("vertex {} is not valid", v); 69 | } 70 | } 71 | 72 | pub fn adj_edge(&self, v: usize) -> &LinkedList { 73 | self.validate_vertex(v); 74 | 75 | &self.adj[v] 76 | } 77 | 78 | pub fn degree(&self, v: usize) -> usize { 79 | self.validate_vertex(v); 80 | 81 | self.adj_edge(v).len() 82 | } 83 | } 84 | 85 | impl Display for AdjList { 86 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 87 | let mut list = String::new(); 88 | for v in 0..self.v { 89 | list.push_str(format!("{}: ", v).as_str()); 90 | for w in &self.adj[v] { 91 | list.push_str(format!("{} ", w).as_str()); 92 | } 93 | list.push('\n'); 94 | } 95 | write!( 96 | f, 97 | "AdjList: \nV: {}, E: {}\nList: \n{}", 98 | self.v, self.e, list 99 | ) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /02-Graph-Basics/06-Adjacency-List/src/main.rs: -------------------------------------------------------------------------------- 1 | mod adjlist; 2 | 3 | use crate::adjlist::AdjList; 4 | 5 | pub fn main() { 6 | let list = AdjList::from("g.txt"); 7 | println!("{}", list); 8 | } 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/08-Adjacency-Set/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter2-p8" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /02-Graph-Basics/08-Adjacency-Set/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter2-p8" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/08-Adjacency-Set/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /02-Graph-Basics/08-Adjacency-Set/src/adjlist.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::collections::LinkedList; 3 | use std::fmt::{Display, Formatter}; 4 | use std::fs; 5 | 6 | #[derive(Debug)] 7 | pub struct AdjList { 8 | v: usize, 9 | e: usize, 10 | adj: Vec>, 11 | } 12 | 13 | impl AdjList { 14 | pub fn from(filename: &str) -> Self { 15 | let file = fs::read_to_string(filename).unwrap(); 16 | let mut iter = file.split("\n").into_iter(); 17 | let mut first_line = iter.next().unwrap().split_whitespace(); 18 | 19 | let v = first_line.next().unwrap().parse::().unwrap(); 20 | let e = first_line.next().unwrap().parse::().unwrap(); 21 | 22 | let mut ret = AdjList { 23 | v, 24 | e, 25 | adj: vec![LinkedList::new(); v as usize], 26 | }; 27 | 28 | while let Some(line) = iter.next() { 29 | if line.len() == 0 { 30 | break; 31 | } 32 | let mut line = line.split_whitespace(); 33 | let x = line.next().unwrap().parse::().unwrap(); 34 | let y = line.next().unwrap().parse::().unwrap(); 35 | ret.validate_vertex(x); 36 | ret.validate_vertex(y); 37 | 38 | if x == y { 39 | panic!("Self Loop is Detected!"); 40 | } 41 | if ret.adj[x].contains(&y) { 42 | panic!("Parallel Edges are Detected!"); 43 | } 44 | 45 | ret.adj[x].push_back(y); 46 | ret.adj[y].push_back(x); 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | pub fn e(&self) -> usize { 53 | self.e 54 | } 55 | 56 | pub fn v(&self) -> usize { 57 | self.v 58 | } 59 | 60 | pub fn has_edge(&self, v1: usize, v2: usize) -> bool { 61 | self.validate_vertex(v1); 62 | self.validate_vertex(v2); 63 | return self.adj[v1].contains(&v2); 64 | } 65 | 66 | fn validate_vertex(&self, v: usize) { 67 | if v >= self.v as usize { 68 | panic!("vertex {} is not valid", v); 69 | } 70 | } 71 | 72 | pub fn adj_edge(&self, v: usize) -> &LinkedList { 73 | self.validate_vertex(v); 74 | 75 | &self.adj[v] 76 | } 77 | 78 | pub fn degree(&self, v: usize) -> usize { 79 | self.adj_edge(v).len() 80 | } 81 | } 82 | 83 | impl Display for AdjList { 84 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 85 | let mut list = String::new(); 86 | for v in 0..self.v { 87 | list.push_str(format!("{}: ", v).as_str()); 88 | for w in &self.adj[v] { 89 | list.push_str(format!("{} ", w).as_str()); 90 | } 91 | list.push('\n'); 92 | } 93 | write!( 94 | f, 95 | "AdjList: \nV: {}, E: {}\nList: \n{}", 96 | self.v, self.e, list 97 | ) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /02-Graph-Basics/08-Adjacency-Set/src/main.rs: -------------------------------------------------------------------------------- 1 | mod adjlist; 2 | mod adjset; 3 | 4 | use crate::adjlist::AdjList; 5 | use crate::adjset::AdjSet; 6 | 7 | pub fn main() { 8 | let list = AdjList::from("g.txt"); 9 | println!("{}", list); 10 | let set = AdjSet::from("g.txt"); 11 | println!("{}", set); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /02-Graph-Basics/09-Graph-Representation-Comparation/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter2-p9" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /02-Graph-Basics/09-Graph-Representation-Comparation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter2-p9" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /02-Graph-Basics/09-Graph-Representation-Comparation/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /02-Graph-Basics/09-Graph-Representation-Comparation/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | use crate::graph::Graph; 4 | 5 | pub fn main() { 6 | let set = Graph::from("g.txt"); 7 | println!("{}", set); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /02-Graph-Basics/README.md: -------------------------------------------------------------------------------- 1 | # 注意事项 2 | 由于Rust标准库没有实现红黑树集合,只有使用B树实现的BTreeSet,出于性能的权衡、且B树实现对空间的占用也较大,最后本项目代码全部使用HashSet实现。 3 | 4 | **请注意HashSet不具有顺序性。** 5 | -------------------------------------------------------------------------------- /03-Graph-DFS/04-Graph-DFS-Implementation/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter3-p4" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /03-Graph-DFS/04-Graph-DFS-Implementation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter3-p4" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /03-Graph-DFS/04-Graph-DFS-Implementation/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /03-Graph-DFS/04-Graph-DFS-Implementation/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod graph_dfs { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn dfs(g: &Graph) -> Vec { 8 | let mut visited = vec![false; g.v()]; 9 | let mut res = Vec::new(); 10 | __dfs(&g, 0, &mut visited, &mut res); 11 | return res; 12 | } 13 | 14 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, res: &mut Vec) { 15 | visited[v] = true; 16 | res.push(v); 17 | 18 | for &w in g.adj_edge(v) { 19 | if visited[w] == false { 20 | __dfs(g, w, visited, res); 21 | } 22 | } 23 | } 24 | } 25 | 26 | use crate::{graph::Graph, graph_dfs::dfs}; 27 | 28 | pub fn main() { 29 | let g = Graph::from("g.txt"); 30 | let res = dfs(&g); 31 | println!("{:?}", res); 32 | } 33 | -------------------------------------------------------------------------------- /03-Graph-DFS/05-Graph-DFS-Improvement/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter3-p5" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /03-Graph-DFS/05-Graph-DFS-Improvement/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter3-p5" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /03-Graph-DFS/05-Graph-DFS-Improvement/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /03-Graph-DFS/05-Graph-DFS-Improvement/src/graph.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::collections::hash_set::Iter; 3 | use std::collections::HashSet; 4 | use std::fmt::{Display, Formatter}; 5 | use std::fs; 6 | 7 | #[derive(Debug)] 8 | pub struct Graph { 9 | v: usize, 10 | e: usize, 11 | adj: Vec>, 12 | } 13 | 14 | impl Graph { 15 | pub fn from(filename: &str) -> Self { 16 | let file = fs::read_to_string(filename).unwrap(); 17 | let mut iter = file.split('\n'); 18 | let mut first_line = iter.next().unwrap().split_whitespace(); 19 | 20 | let v = first_line.next().unwrap().parse::().unwrap(); 21 | let e = first_line.next().unwrap().parse::().unwrap(); 22 | 23 | let mut ret = Graph { 24 | v, 25 | e, 26 | adj: vec![HashSet::new(); v as usize], 27 | }; 28 | 29 | for line in iter { 30 | if line.is_empty() { 31 | break; 32 | } 33 | let mut line = line.split_whitespace(); 34 | let x = line.next().unwrap().parse::().unwrap(); 35 | let y = line.next().unwrap().parse::().unwrap(); 36 | ret.validate_vertex(x); 37 | ret.validate_vertex(y); 38 | 39 | if x == y { 40 | panic!("Self Loop is Detected!"); 41 | } 42 | if ret.adj[x].contains(&y) { 43 | panic!("Parallel Edges are Detected!"); 44 | } 45 | 46 | ret.adj[x].insert(y); 47 | ret.adj[y].insert(x); 48 | } 49 | 50 | ret 51 | } 52 | 53 | pub fn e(&self) -> usize { 54 | self.e 55 | } 56 | 57 | pub fn v(&self) -> usize { 58 | self.v 59 | } 60 | 61 | pub fn has_edge(&self, v1: usize, v2: usize) -> bool { 62 | self.validate_vertex(v1); 63 | self.validate_vertex(v2); 64 | self.adj[v1].contains(&v2) 65 | } 66 | 67 | fn validate_vertex(&self, v: usize) { 68 | if v >= self.v as usize { 69 | panic!("vertex {} is not valid", v); 70 | } 71 | } 72 | 73 | pub fn adj_edge(&self, v: usize) -> Iter<'_, usize> { 74 | self.validate_vertex(v); 75 | 76 | self.adj[v].iter() 77 | } 78 | 79 | pub fn degree(&self, v: usize) -> usize { 80 | self.validate_vertex(v); 81 | 82 | self.adj[v].len() 83 | } 84 | } 85 | 86 | impl Display for Graph { 87 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 88 | let mut list = String::new(); 89 | for v in 0..self.v { 90 | list.push_str(format!("{}: ", v).as_str()); 91 | for w in &self.adj[v] { 92 | list.push_str(format!("{} ", w).as_str()); 93 | } 94 | list.push('\n'); 95 | } 96 | write!( 97 | f, 98 | "AdjList: \nV: {}, E: {}\nList: \n{}", 99 | self.v, self.e, list 100 | ) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /03-Graph-DFS/05-Graph-DFS-Improvement/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod graph_dfs { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn dfs(g: &Graph) -> Vec { 8 | let mut visited = vec![false; g.v()]; 9 | let mut res = Vec::new(); 10 | for v in 0..g.v() { 11 | if visited[v] == false { 12 | __dfs(&g, v, &mut visited, &mut res); 13 | } 14 | } 15 | return res; 16 | } 17 | 18 | pub fn post_dfs(g: &Graph) -> Vec { 19 | let mut visited = vec![false; g.v()]; 20 | let mut res = Vec::new(); 21 | for v in 0..g.v() { 22 | if visited[v] == false { 23 | __post_dfs(&g, v, &mut visited, &mut res); 24 | } 25 | } 26 | return res; 27 | } 28 | 29 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, res: &mut Vec) { 30 | visited[v] = true; 31 | res.push(v); 32 | 33 | for &w in g.adj_edge(v) { 34 | if visited[w] == false { 35 | __dfs(g, w, visited, res); 36 | } 37 | } 38 | } 39 | 40 | fn __post_dfs(g: &Graph, v: usize, visited: &mut Vec, res: &mut Vec) { 41 | visited[v] = true; 42 | 43 | for &w in g.adj_edge(v) { 44 | if visited[w] == false { 45 | __post_dfs(g, w, visited, res); 46 | } 47 | } 48 | 49 | res.push(v); 50 | } 51 | } 52 | 53 | use crate::{ 54 | graph::Graph, 55 | graph_dfs::{dfs, post_dfs}, 56 | }; 57 | 58 | pub fn main() { 59 | let g = Graph::from("g.txt"); 60 | let res = dfs(&g); 61 | println!("{:?}", res); 62 | 63 | let res2 = post_dfs(&g); 64 | println!("{:?}", res2); 65 | } 66 | -------------------------------------------------------------------------------- /03-Graph-DFS/README.md: -------------------------------------------------------------------------------- 1 | # 注意事项 2 | 由于原课程使用JAVA实现,需要使用面向对象的方式来实现对应的算法。而Rust是支持过程式的语言,因此我们这里会采取类似于C/C++的过程式写法,将算法封装成自由函数。同时为了满足封装性,我们将算法相关的内容封装在一个模块中(`mod`) 3 | 4 | 每一章节的实现会写入`main.rs`中, 示例如下: 5 | 6 | ```rust 7 | mod name_of_algo { 8 | fn impl_of_algo (...) -> ... { 9 | ... 10 | } 11 | } 12 | 13 | pub fn main() { 14 | ... 15 | use_of_algo(); 16 | ... 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/01-Connected-Components-Count/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p1" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/01-Connected-Components-Count/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/01-Connected-Components-Count/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/01-Connected-Components-Count/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod cc { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn count(g: &Graph) -> i32 { 8 | let mut visited = vec![false; g.v()]; 9 | let mut cc_count = 0; 10 | for v in 0..g.v() { 11 | if !visited[v] { 12 | __count(g, v, &mut visited); 13 | cc_count += 1; 14 | } 15 | } 16 | cc_count 17 | } 18 | 19 | fn __count(g: &Graph, v: usize, visited: &mut Vec) { 20 | visited[v] = true; 21 | 22 | for &w in g.adj_edge(v) { 23 | if !visited[w] { 24 | __count(g, w, visited); 25 | } 26 | } 27 | } 28 | } 29 | 30 | pub fn main() {} 31 | 32 | #[test] 33 | pub fn cc_test() { 34 | let g = Graph::from("g.txt"); 35 | assert_eq!(cc::count(&g), 2); 36 | } 37 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/02-Connected-Components/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p2" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/02-Connected-Components/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p2" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/02-Connected-Components/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/02-Connected-Components/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod cc { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn count(g: &Graph) -> i32 { 8 | let mut visited = vec![-1; g.v()]; 9 | let mut cc_count = 0; 10 | for v in 0..g.v() { 11 | if visited[v] == -1 { 12 | __count(g, v, &mut visited, cc_count); 13 | cc_count += 1; 14 | } 15 | } 16 | 17 | println!("{:?}", visited); 18 | cc_count 19 | } 20 | 21 | fn __count(g: &Graph, v: usize, visited: &mut Vec, ccid: i32) { 22 | visited[v] = ccid; 23 | 24 | for &w in g.adj_edge(v) { 25 | if visited[w] == -1 { 26 | __count(g, w, visited, ccid); 27 | } 28 | } 29 | } 30 | } 31 | 32 | pub fn main() {} 33 | 34 | #[test] 35 | pub fn cc_test() { 36 | let g = Graph::from("g.txt"); 37 | assert_eq!(cc::count(&g), 2); 38 | } 39 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/03-More-about-Connected-Components/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p3" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/03-More-about-Connected-Components/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/03-More-about-Connected-Components/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/03-More-about-Connected-Components/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod cc { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn dfs(g: &Graph) -> (Vec, i32) { 8 | let mut visited = vec![-1; g.v()]; 9 | let mut cc_count = 0; 10 | for v in 0..g.v() { 11 | if visited[v] == -1 { 12 | __dfs(g, v, &mut visited, cc_count); 13 | cc_count += 1; 14 | } 15 | } 16 | 17 | (visited, cc_count) 18 | } 19 | 20 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, ccid: i32) { 21 | visited[v] = ccid; 22 | 23 | for &w in g.adj_edge(v) { 24 | if visited[w] == -1 { 25 | __dfs(g, w, visited, ccid); 26 | } 27 | } 28 | } 29 | 30 | pub fn component(g: &Graph) -> Vec> { 31 | let (visited, cnt) = dfs(g); 32 | let mut res: Vec> = vec![vec![]; cnt as usize]; 33 | 34 | for v in 0..g.v() { 35 | res[visited[v] as usize].push(v); 36 | } 37 | 38 | res 39 | } 40 | 41 | pub fn is_connected(g: &Graph, v: usize, w: usize) -> bool { 42 | let (visited, _) = dfs(g); 43 | 44 | visited[v] == visited[w] 45 | } 46 | } 47 | 48 | pub fn main() {} 49 | 50 | #[test] 51 | pub fn cc_test() { 52 | let g = Graph::from("g.txt"); 53 | assert_eq!(cc::dfs(&g).1, 2); 54 | assert_eq!(cc::is_connected(&g, 0, 6), true); 55 | assert_eq!(cc::is_connected(&g, 0, 5), false); 56 | let gc = cc::component(&g); 57 | for i in 0..gc.len() { 58 | print!("{}: ", i); 59 | for v in &gc[i] { 60 | print!("{} ", v); 61 | } 62 | println!(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/05-Single-Source-Path/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p5" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/05-Single-Source-Path/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p5" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/05-Single-Source-Path/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/05-Single-Source-Path/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod single_source_path { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn dfs(g: &Graph, s: usize) -> Vec { 8 | let mut visited = vec![false; g.v()]; 9 | let mut pre = vec![-1; g.v()]; 10 | 11 | __dfs(g, s, &mut visited, &mut pre, s); 12 | pre 13 | } 14 | 15 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, pre: &mut Vec, pre_v: usize) { 16 | visited[v] = true; 17 | pre[v] = pre_v as i32; 18 | 19 | for &w in g.adj_edge(v) { 20 | if !visited[w] { 21 | __dfs(g, w, visited, pre, v); 22 | } 23 | } 24 | } 25 | 26 | pub fn is_connected_to(g: &Graph, s: usize, w: usize) -> bool { 27 | let pre = dfs(g, s); 28 | pre[w] != -1 29 | } 30 | 31 | pub fn path(g: &Graph, s: usize, w: usize) -> Vec { 32 | let pre = dfs(g, s); 33 | let mut res = Vec::new(); 34 | 35 | if pre[w] == -1 { 36 | return res; 37 | } 38 | 39 | let mut cur = w; 40 | while cur != s { 41 | res.push(cur); 42 | cur = pre[cur] as usize; 43 | } 44 | res.push(s); 45 | res.reverse(); 46 | 47 | res 48 | } 49 | } 50 | 51 | use crate::{ 52 | graph::Graph, 53 | single_source_path::{is_connected_to, path}, 54 | }; 55 | 56 | pub fn main() { 57 | let g = Graph::from("g.txt"); 58 | println!("{}", is_connected_to(&g, 0, 6)); 59 | println!("{}", is_connected_to(&g, 0, 5)); 60 | println!("0 -> 6: {:?}", path(&g, 0, 6)); 61 | println!("0 -> 5: {:?}", path(&g, 0, 5)); 62 | } 63 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/08-Path-Improvement/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p8" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/08-Path-Improvement/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p8" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/08-Path-Improvement/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/08-Path-Improvement/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod path { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn dfs(g: &Graph, s: usize, t: usize) -> Vec { 8 | g.validate_vertex(s); 9 | g.validate_vertex(t); 10 | 11 | let mut visited = vec![false; g.v()]; 12 | let mut pre = vec![-1; g.v()]; 13 | 14 | __dfs(g, s, &mut visited, &mut pre, s, t); 15 | pre 16 | } 17 | 18 | fn __dfs( 19 | g: &Graph, 20 | v: usize, 21 | visited: &mut Vec, 22 | pre: &mut Vec, 23 | pre_v: usize, 24 | t: usize, 25 | ) -> bool { 26 | visited[v] = true; 27 | pre[v] = pre_v as i32; 28 | 29 | if v == t { 30 | return true; 31 | } 32 | 33 | for &w in g.adj_edge(v) { 34 | if !visited[w] && __dfs(g, w, visited, pre, v, t) { 35 | return true; 36 | } 37 | } 38 | 39 | false 40 | } 41 | 42 | pub fn is_connected_to(g: &Graph, s: usize, w: usize) -> bool { 43 | let pre = dfs(g, s, w); 44 | pre[w] != -1 45 | } 46 | 47 | pub fn path(g: &Graph, s: usize, w: usize) -> Vec { 48 | let pre = dfs(g, s, w); 49 | let mut res = Vec::new(); 50 | 51 | if pre[w] == -1 { 52 | return res; 53 | } 54 | 55 | let mut cur = w; 56 | while cur != s { 57 | res.push(cur); 58 | cur = pre[cur] as usize; 59 | } 60 | res.push(s); 61 | res.reverse(); 62 | 63 | res 64 | } 65 | } 66 | 67 | use crate::{ 68 | graph::Graph, 69 | path::{is_connected_to, path}, 70 | }; 71 | 72 | pub fn main() { 73 | let g = Graph::from("g.txt"); 74 | println!("{}", is_connected_to(&g, 0, 6)); 75 | println!("{}", is_connected_to(&g, 0, 5)); 76 | println!("0 -> 6: {:?}", path(&g, 0, 6)); 77 | println!("0 -> 5: {:?}", path(&g, 0, 5)); 78 | } 79 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/09-Cycle-Detection/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p9" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/09-Cycle-Detection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p9" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/09-Cycle-Detection/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/09-Cycle-Detection/g2.txt: -------------------------------------------------------------------------------- 1 | 7 5 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 6 7 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/09-Cycle-Detection/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod cycle_detection { 4 | 5 | use crate::graph::Graph; 6 | 7 | pub fn has_cycle(g: &Graph) -> bool { 8 | let mut visited = vec![false; g.v()]; 9 | for v in 0..g.v() { 10 | if !visited[v] && __dfs(g, v, &mut visited, v) { 11 | return true; 12 | } 13 | } 14 | 15 | false 16 | } 17 | 18 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, pre: usize) -> bool { 19 | visited[v] = true; 20 | 21 | for &w in g.adj_edge(v) { 22 | if !visited[w] { 23 | __dfs(g, w, visited, v); 24 | } else if w != pre { 25 | return true; 26 | } 27 | } 28 | 29 | false 30 | } 31 | } 32 | 33 | pub fn main() {} 34 | 35 | #[test] 36 | pub fn cycle_detection_test() { 37 | let g = Graph::from("g.txt"); 38 | let g2 = Graph::from("g2.txt"); 39 | 40 | assert_eq!(has_cycle(&g), true); 41 | assert_eq!(has_cycle(&g2), false); 42 | } 43 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter4-p10" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter4-p10" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/g.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/g2.txt: -------------------------------------------------------------------------------- 1 | 4 6 2 | 0 1 3 | 0 2 4 | 0 3 5 | 1 2 6 | 1 3 7 | 2 3 -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/g3.txt: -------------------------------------------------------------------------------- 1 | 4 4 2 | 0 1 3 | 0 3 4 | 1 2 5 | 2 3 -------------------------------------------------------------------------------- /04-Graph-DFS-Applications/11-Bipartition-Detection/src/main.rs: -------------------------------------------------------------------------------- 1 | mod graph; 2 | 3 | mod bipartition_detection { 4 | 5 | use crate::graph::Graph; 6 | 7 | /// `colors`: 表示颜色 8 | /// - 0 -> blue 9 | /// - 1 -> green 10 | pub fn is_bipartition(g: &Graph) -> (bool, Option>) { 11 | let mut visited = vec![false; g.v()]; 12 | let mut colors = vec![-1; g.v()]; 13 | for v in 0..g.v() { 14 | if !visited[v] && !__dfs(g, v, &mut visited, &mut colors, 0) { 15 | return (false, None); 16 | } 17 | } 18 | 19 | (true, Some(colors)) 20 | } 21 | 22 | fn __dfs( 23 | g: &Graph, 24 | v: usize, 25 | visited: &mut Vec, 26 | colors: &mut Vec, 27 | color: i32, 28 | ) -> bool { 29 | visited[v] = true; 30 | colors[v] = color; 31 | 32 | for &w in g.adj_edge(v) { 33 | if !visited[w] { 34 | if !__dfs(g, w, visited, colors, 1 - color) { 35 | return false; 36 | } 37 | } else if colors[w] == colors[v] { 38 | return false; 39 | } 40 | } 41 | 42 | true 43 | } 44 | } 45 | 46 | pub fn main() {} 47 | 48 | #[test] 49 | pub fn cycle_detection_test() { 50 | let g = Graph::from("g.txt"); 51 | let g2 = Graph::from("g2.txt"); 52 | let g3 = Graph::from("g3.txt"); 53 | 54 | assert_eq!(is_bipartition(&g), true); 55 | assert_eq!(is_bipartition(&g2), false); 56 | assert_eq!(is_bipartition(&g3), true); 57 | } 58 | -------------------------------------------------------------------------------- /05-Graph-BFS/02-BFS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter5-2" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /05-Graph-BFS/02-BFS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter5-2" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /05-Graph-BFS/02-BFS/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /05-Graph-BFS/02-BFS/src/graph_bfs.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::graph::Graph; 4 | 5 | /// Interface: Bfs 6 | /// we need to provide a `bfs` method to do bfs search and returen iterator of 7 | /// bfs search result 8 | pub trait Bfs { 9 | fn bfs(&mut self, s: usize) -> Box>; 10 | } 11 | 12 | pub struct GraphBFS { 13 | graph: Graph, 14 | visited: Vec, 15 | res: Vec, 16 | } 17 | 18 | impl GraphBFS { 19 | pub fn new(graph: Graph) -> Self { 20 | let visited = vec![false; graph.v()]; 21 | let res = Vec::new(); 22 | Self { 23 | graph, 24 | visited, 25 | res, 26 | } 27 | } 28 | } 29 | 30 | impl Bfs for GraphBFS { 31 | fn bfs(&mut self, source: usize) -> Box> { 32 | // inner bfs, start from s 33 | let mut bfs_inner = |s| { 34 | // check if `s` is visited before 35 | // MUST do this in `bfs_inner` because we have mutable access inside 36 | // closure, so we can't have a immutable access outside 37 | if self.visited[s] { 38 | return; 39 | } 40 | 41 | let mut q = VecDeque::new(); 42 | q.push_back(s); 43 | self.visited[s] = true; 44 | 45 | while !q.is_empty() { 46 | let v = q.pop_front().unwrap(); 47 | self.res.push(v); 48 | for &next in self.graph.adj_edge(v) { 49 | if !self.visited[next] { 50 | q.push_back(next); 51 | self.visited[next] = true; 52 | } 53 | } 54 | } 55 | }; 56 | 57 | // we should search first from s 58 | // and if there's some v we can't reach, search latter 59 | bfs_inner(source); 60 | 61 | for v in 0..self.graph.v() { 62 | bfs_inner(v); 63 | } 64 | 65 | Box::new(self.res.clone().into_iter()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /05-Graph-BFS/02-BFS/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use graph_bfs::{Bfs, GraphBFS}; 3 | 4 | mod graph; 5 | mod graph_bfs; 6 | 7 | fn main() { 8 | let g = Graph::from_file("g.txt"); 9 | let mut graph_bfs = GraphBFS::new(g); 10 | let res = graph_bfs.bfs(0); 11 | print!("bfs result: "); 12 | for v in res { 13 | print!("{v} "); 14 | } 15 | println!(); 16 | } 17 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter5-3" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter5-3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/g1.txt: -------------------------------------------------------------------------------- 1 | 7 7 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | 5 6 9 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/src/graph_bfs.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::graph::Graph; 4 | 5 | pub trait SingleSourcePath { 6 | fn single_source_path(&mut self); 7 | fn is_connected(&mut self, t: usize) -> bool; 8 | fn path(&mut self, t: usize) -> Box>; 9 | } 10 | 11 | pub struct GraphBFS { 12 | source: usize, 13 | graph: Graph, 14 | visited: Vec, 15 | pre: Vec, 16 | is_computed: bool, 17 | } 18 | 19 | impl GraphBFS { 20 | pub fn new(source: usize, graph: Graph) -> Self { 21 | let visited = vec![false; graph.v()]; 22 | let pre = vec![source; graph.v()]; 23 | Self { 24 | source, 25 | graph, 26 | visited, 27 | pre, 28 | is_computed: false, 29 | } 30 | } 31 | } 32 | 33 | impl SingleSourcePath for GraphBFS { 34 | fn single_source_path(&mut self) { 35 | let mut q = VecDeque::new(); 36 | let s = self.source; 37 | q.push_back(s); 38 | self.visited[s] = true; 39 | self.pre[s] = s; 40 | 41 | while !q.is_empty() { 42 | let v = q.pop_front().unwrap(); 43 | for &next in self.graph.adj_edge(v) { 44 | if !self.visited[next] { 45 | q.push_back(next); 46 | self.visited[next] = true; 47 | self.pre[next] = v; 48 | } 49 | } 50 | } 51 | self.is_computed = true; 52 | } 53 | 54 | fn is_connected(&mut self, t: usize) -> bool { 55 | self.graph.validate_vertex(t); 56 | if !self.is_computed { 57 | self.single_source_path(); 58 | } 59 | self.visited[t] 60 | } 61 | 62 | fn path(&mut self, t: usize) -> Box> { 63 | self.graph.validate_vertex(t); 64 | if !self.is_computed { 65 | self.single_source_path(); 66 | } 67 | 68 | let mut res = Vec::new(); 69 | if !self.is_connected(t) { 70 | return Box::new(res.into_iter()); 71 | } 72 | 73 | let mut cur = t; 74 | while cur != self.source { 75 | res.push(cur); 76 | cur = self.pre[cur]; 77 | } 78 | res.push(self.source); 79 | res.reverse(); 80 | 81 | Box::new(res.into_iter()) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /05-Graph-BFS/03-Single-Source-Path-BFS/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use graph_bfs::GraphBFS; 3 | 4 | use crate::graph_bfs::SingleSourcePath; 5 | 6 | mod graph; 7 | mod graph_bfs; 8 | 9 | fn main() { 10 | let g = Graph::from_file("g1.txt"); 11 | let mut graph_bfs = GraphBFS::new(0, g); 12 | graph_bfs.single_source_path(); 13 | let res = graph_bfs.path(6); 14 | print!("path 0->6 result: "); 15 | // let vec: Vec = res.collect(); 16 | // dbg!(vec); 17 | for v in res { 18 | print!("{v} "); 19 | } 20 | println!(); 21 | } 22 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter5-9" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter5-9" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/g.txt: -------------------------------------------------------------------------------- 1 | 7 9 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 6 6 | 2 3 7 | 2 5 8 | 3 4 9 | 4 5 10 | 5 6 11 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/g1.txt: -------------------------------------------------------------------------------- 1 | 7 7 2 | 0 1 3 | 0 2 4 | 1 3 5 | 1 4 6 | 2 3 7 | 2 6 8 | 5 6 9 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/src/graph_bfs.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::{ 4 | graph::Graph, 5 | unweighted_shortest_path::{SingleSourcePath, Usssp}, 6 | }; 7 | 8 | pub struct GraphBFS { 9 | source: usize, 10 | graph: Graph, 11 | visited: Vec, 12 | pre: Vec, 13 | dis: Vec, 14 | is_computed: bool, 15 | } 16 | 17 | impl GraphBFS { 18 | pub fn new(source: usize, graph: Graph) -> Self { 19 | let visited = vec![false; graph.v()]; 20 | let pre = vec![source; graph.v()]; 21 | let dis = vec![-1; graph.v()]; 22 | Self { 23 | source, 24 | graph, 25 | visited, 26 | pre, 27 | dis, 28 | is_computed: false, 29 | } 30 | } 31 | } 32 | 33 | impl SingleSourcePath for GraphBFS { 34 | fn single_source_path(&mut self) { 35 | let mut q = VecDeque::new(); 36 | let s = self.source; 37 | q.push_back(s); 38 | self.visited[s] = true; 39 | self.pre[s] = s; 40 | self.dis[s] = 0; 41 | 42 | while !q.is_empty() { 43 | let v = q.pop_front().unwrap(); 44 | for &next in self.graph.adj_edge(v) { 45 | if !self.visited[next] { 46 | q.push_back(next); 47 | self.visited[next] = true; 48 | self.pre[next] = v; 49 | self.dis[next] = self.dis[v] + 1; 50 | } 51 | } 52 | } 53 | self.is_computed = true; 54 | 55 | // just for debug, print `dis` 56 | for i in &self.dis { 57 | print!("{i} "); 58 | } 59 | println!(); 60 | } 61 | 62 | fn is_connected(&mut self, t: usize) -> bool { 63 | self.graph.validate_vertex(t); 64 | if !self.is_computed { 65 | self.single_source_path(); 66 | } 67 | self.visited[t] 68 | } 69 | 70 | fn path(&mut self, t: usize) -> Box> { 71 | self.graph.validate_vertex(t); 72 | if !self.is_computed { 73 | self.single_source_path(); 74 | } 75 | 76 | let mut res = Vec::new(); 77 | if !self.is_connected(t) { 78 | return Box::new(res.into_iter()); 79 | } 80 | 81 | let mut cur = t; 82 | while cur != self.source { 83 | res.push(cur); 84 | cur = self.pre[cur]; 85 | } 86 | res.push(self.source); 87 | res.reverse(); 88 | 89 | Box::new(res.into_iter()) 90 | } 91 | } 92 | 93 | impl Usssp for GraphBFS { 94 | fn dis(&mut self, t: usize) -> i32 { 95 | if !self.is_computed { 96 | self.single_source_path(); 97 | } 98 | self.graph.validate_vertex(t); 99 | self.dis[t] 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use graph_bfs::GraphBFS; 3 | 4 | use crate::unweighted_shortest_path::{SingleSourcePath, Usssp}; 5 | 6 | mod graph; 7 | mod graph_bfs; 8 | mod unweighted_shortest_path; 9 | 10 | fn main() { 11 | let g = Graph::from_file("g1.txt"); 12 | let mut graph_bfs = GraphBFS::new(0, g); 13 | graph_bfs.single_source_path(); 14 | let res = graph_bfs.path(6); 15 | print!("path 0->6 result: "); 16 | // let vec: Vec = res.collect(); 17 | // dbg!(vec); 18 | for v in res { 19 | print!("{v} "); 20 | } 21 | println!(); 22 | println!("{}", graph_bfs.dis(6)) 23 | } 24 | -------------------------------------------------------------------------------- /05-Graph-BFS/09-Unweighted-Shortest-Path/src/unweighted_shortest_path.rs: -------------------------------------------------------------------------------- 1 | pub trait SingleSourcePath { 2 | fn single_source_path(&mut self); 3 | fn is_connected(&mut self, t: usize) -> bool; 4 | fn path(&mut self, t: usize) -> Box>; 5 | } 6 | 7 | pub trait Usssp: SingleSourcePath { 8 | fn dis(&mut self, t: usize) -> i32; 9 | } 10 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/01-Leetcode-Graph-Basics/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter06-01" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/01-Leetcode-Graph-Basics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter06-01" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/01-Leetcode-Graph-Basics/src/main.rs: -------------------------------------------------------------------------------- 1 | pub struct Solution; 2 | impl Solution { 3 | pub fn is_bipartite(graph: Vec>) -> bool { 4 | let V = graph.len(); 5 | let mut visited = vec![false; V]; 6 | let mut color = vec![-1; V]; 7 | 8 | for v in 0..V { 9 | if !visited[v] && !Solution::dfs(v as i32, 0, &graph, &mut visited, &mut color) { 10 | return false; 11 | } 12 | } 13 | 14 | true 15 | } 16 | 17 | fn dfs( 18 | v: i32, 19 | color: i32, 20 | graph: &Vec>, 21 | visited: &mut Vec, 22 | colors: &mut Vec, 23 | ) -> bool { 24 | // chang to usize inorder to index the vec 25 | let v = v as usize; 26 | 27 | visited[v] = true; 28 | colors[v] = color; 29 | 30 | for &w in &graph[v] { 31 | let w = w as usize; 32 | if !visited[w] { 33 | if !Solution::dfs(w as i32, 1 - color, graph, visited, colors) { 34 | return false; 35 | } 36 | } else { 37 | if colors[v] == colors[w] { 38 | return false; 39 | } 40 | } 41 | } 42 | 43 | true 44 | } 45 | } 46 | 47 | fn main() {} 48 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/03-Graph-Construction/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter06-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/03-Graph-Construction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter06-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/03-Graph-Construction/src/main.rs: -------------------------------------------------------------------------------- 1 | mod solution; 2 | 3 | fn main() { 4 | println!("Hello, world!"); 5 | } 6 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/03-Graph-Construction/src/solution.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | struct Solution; 4 | 5 | impl Solution { 6 | pub fn max_area_of_island(grid: Vec>) -> i32 { 7 | let dir = vec![vec![-1, 0], vec![0, 1], vec![1, 0], vec![0, -1]]; 8 | let r = grid.len(); 9 | let c = grid[0].len(); 10 | let mut g = vec![HashSet::new(); r * c]; 11 | let mut visited = vec![false; g.len()]; 12 | 13 | let in_area = |x, y| -> bool { x >= 0 && y >= 0 && x < r as i32 && y < c as i32 }; 14 | 15 | let mut construct_graph = || { 16 | for v in 0..g.len() { 17 | let x = v / c; 18 | let y = v % c; 19 | if grid[x][y] == 1 { 20 | for d in &dir { 21 | let nextx = x as i32 + d[0]; 22 | let nexty = y as i32 + d[1]; 23 | if in_area(nextx, nexty) && grid[nextx as usize][nexty as usize] == 1 { 24 | let next = nextx as usize * c + nexty as usize; 25 | g[v].insert(next); 26 | g[next].insert(v); 27 | } 28 | } 29 | } 30 | } 31 | }; 32 | 33 | construct_graph(); 34 | 35 | let mut res = 0; 36 | 37 | for v in 0..g.len() { 38 | let x = v / c; 39 | let y = v % c; 40 | if !visited[v] && grid[x][y] == 1 { 41 | res = i32::max(res, Solution::dfs(v, &g, &mut visited)); 42 | } 43 | } 44 | 45 | res 46 | } 47 | 48 | fn dfs(v: usize, g: &Vec>, visited: &mut Vec) -> i32 { 49 | visited[v] = true; 50 | let mut res = 1; 51 | for &w in &g[v] { 52 | if !visited[w] { 53 | res += Solution::dfs(w, g, visited); 54 | } 55 | } 56 | res 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/04-Flood-Fill/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter06-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/04-Flood-Fill/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter06-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/04-Flood-Fill/src/main.rs: -------------------------------------------------------------------------------- 1 | mod solution; 2 | mod solution2; 3 | 4 | fn main() { 5 | println!("Hello, world!"); 6 | } 7 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/04-Flood-Fill/src/solution.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | struct Solution; 4 | 5 | impl Solution { 6 | pub fn max_area_of_island(grid: Vec>) -> i32 { 7 | let dir = vec![vec![-1, 0], vec![0, 1], vec![1, 0], vec![0, -1]]; 8 | let r = grid.len(); 9 | let c = grid[0].len(); 10 | let mut g = vec![HashSet::new(); r * c]; 11 | let mut visited = vec![false; g.len()]; 12 | 13 | let in_area = |x, y| -> bool { x >= 0 && y >= 0 && x < r as i32 && y < c as i32 }; 14 | 15 | let mut construct_graph = || { 16 | for v in 0..g.len() { 17 | let x = v / c; 18 | let y = v % c; 19 | if grid[x][y] == 1 { 20 | for d in &dir { 21 | let nextx = x as i32 + d[0]; 22 | let nexty = y as i32 + d[1]; 23 | if in_area(nextx, nexty) && grid[nextx as usize][nexty as usize] == 1 { 24 | let next = nextx as usize * c + nexty as usize; 25 | g[v].insert(next); 26 | g[next].insert(v); 27 | } 28 | } 29 | } 30 | } 31 | }; 32 | 33 | construct_graph(); 34 | 35 | let mut res = 0; 36 | 37 | for v in 0..g.len() { 38 | let x = v / c; 39 | let y = v % c; 40 | if !visited[v] && grid[x][y] == 1 { 41 | res = i32::max(res, Solution::dfs(v, &g, &mut visited)); 42 | } 43 | } 44 | 45 | res 46 | } 47 | 48 | fn dfs(v: usize, g: &Vec>, visited: &mut Vec) -> i32 { 49 | visited[v] = true; 50 | let mut res = 1; 51 | for &w in &g[v] { 52 | if !visited[w] { 53 | res += Solution::dfs(w, g, visited); 54 | } 55 | } 56 | res 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/04-Flood-Fill/src/solution2.rs: -------------------------------------------------------------------------------- 1 | struct Solution; 2 | 3 | impl Solution { 4 | pub fn max_area_of_island(grid: Vec>) -> i32 { 5 | let dir = vec![vec![-1, 0], vec![0, 1], vec![1, 0], vec![0, -1]]; 6 | let r = grid.len(); 7 | let c = grid[0].len(); 8 | let mut visited = vec![vec![false; c]; r]; 9 | 10 | let mut res = 0; 11 | for x in 0..r { 12 | for y in 0..c { 13 | if !visited[x][y] && grid[x][y] == 1 { 14 | res = i32::max( 15 | res, 16 | Solution::dfs(x, y, &mut visited, &dir, r as i32, c as i32, &grid), 17 | ); 18 | } 19 | } 20 | } 21 | res 22 | } 23 | 24 | fn dfs( 25 | x: usize, 26 | y: usize, 27 | visited: &mut Vec>, 28 | dir: &Vec>, 29 | r: i32, 30 | c: i32, 31 | grid: &Vec>, 32 | ) -> i32 { 33 | visited[x][y] = true; 34 | let mut res = 1; 35 | for d in dir { 36 | let x = x as i32 + d[0]; 37 | let y = y as i32 + d[1]; 38 | if x >= 0 && y >= 0 && x < r && y < c { 39 | let x = x as usize; 40 | let y = y as usize; 41 | if !visited[x][y] && grid[x][y] == 1 { 42 | res += Solution::dfs(x, y, visited, dir, r, c, grid); 43 | } 44 | } 45 | } 46 | res 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /06-Graph-Modelling-and-Floodfill/README.md: -------------------------------------------------------------------------------- 1 | # 注意⚠️ 2 | 3 | 在课程的介绍中,提到了我们可以用类的成员变量和函数参数两种方法来表示许多需要的 4 | 辅助变量,例如`visited`等。但是由于Rust的结构体方法和数据是分开定义的,Leetcode 5 | 提供的仅有函数接口,因此我们并不能使用成员变量的方式来定义辅助变量。根据Rust的 6 | 特性,我们有以下两种方法: 7 | 8 | ## 1. 在参数中定义,然后使用时传入 9 | 这是最通用的方法,也比较常见,缺点是有时会需要非常多变量,例如`visited`、 10 | 矩阵的长和宽、染色`color`、遍历方向`dir`... 11 | 12 | 我们基本上也选择参数定义的方式来解决问题。 13 | 14 | ## 2. 使用闭包 15 | 闭包是Rust独特的特性之一,闭包能够捕获当前的作用域中的变量,变相起到了类成员变量 16 | 的作用。但是闭包是有一定缺陷的,其最主要的问题在于,不能够递归的调用,因此递归 17 | 写法的dfs就不能采用这种方式。 18 | 19 | 当可以简化代码,使用闭包的时候,我会使用闭包。 20 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/01-Leetcode-BFS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-01" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/01-Leetcode-BFS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-01" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/01-Leetcode-BFS/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::LinkedList; 2 | 3 | struct Solution; 4 | 5 | impl Solution { 6 | pub fn shortest_path_binary_matrix(grid: Vec>) -> i32 { 7 | let dirs = vec![ 8 | vec![0, 1], 9 | vec![0, -1], 10 | vec![1, 0], 11 | vec![1, 1], 12 | vec![1, -1], 13 | vec![-1, 0], 14 | vec![-1, 1], 15 | vec![-1, -1], 16 | ]; 17 | let r = grid.len(); 18 | let c = grid[0].len(); 19 | let mut visited = vec![vec![false; c]; r]; 20 | let mut dis = vec![vec![1; c]; r]; 21 | 22 | // cannot reach 23 | if grid[0][0] == 1 { 24 | return -1; 25 | } 26 | 27 | // only one point 28 | if r == c && r == 1 { 29 | return 1; 30 | } 31 | 32 | let in_area = |x, y| x >= 0 && x < r as i32 && y >= 0 && y < c as i32; 33 | 34 | let mut q = LinkedList::new(); 35 | q.push_back(0); 36 | visited[0][0] = true; 37 | dis[0][0] = 1; 38 | while !q.is_empty() { 39 | let cur = q.pop_front().unwrap(); 40 | let curx = cur / c as i32; 41 | let cury = cur % c as i32; 42 | for dir in &dirs { 43 | let nextx = curx + dir[0]; 44 | let nexty = cury + dir[1]; 45 | if in_area(nextx, nexty) 46 | && !visited[nextx as usize][nexty as usize] 47 | && grid[nextx as usize][nexty as usize] == 0 48 | { 49 | q.push_back(nextx * (c as i32) + nexty); 50 | 51 | let (nextx, nexty) = (nextx as usize, nexty as usize); 52 | visited[nextx][nexty] = true; 53 | dis[nextx][nexty] = dis[curx as usize][cury as usize] + 1; 54 | 55 | if nextx == c - 1 && nexty == r - 1 { 56 | return dis[nextx][nexty]; 57 | } 58 | } 59 | } 60 | } 61 | 62 | -1 63 | } 64 | } 65 | 66 | fn main() {} 67 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/03-States/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/03-States/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/03-States/src/main.rs: -------------------------------------------------------------------------------- 1 | // Leetcode 752 2 | use std::collections::{HashMap, HashSet, LinkedList}; 3 | use std::iter::FromIterator; 4 | 5 | struct Solution; 6 | 7 | impl Solution { 8 | pub fn open_lock(deadends: Vec, target: String) -> i32 { 9 | let deadset: HashSet = HashSet::from_iter(deadends.into_iter()); 10 | 11 | // special situations 12 | if deadset.contains("0000") || deadset.contains(&target) { 13 | return -1; 14 | } 15 | if target == "0000" { 16 | return 0; 17 | } 18 | 19 | // BFS 20 | let mut q = LinkedList::new(); 21 | q.push_back("0000".to_string()); 22 | 23 | let mut visited: HashMap = HashMap::new(); 24 | visited.insert("0000".to_string(), 0); 25 | 26 | while !q.is_empty() { 27 | let curs = q.pop_front().unwrap(); 28 | let mut curarray: Vec = curs.chars().collect(); 29 | let mut nexts = Vec::new(); 30 | 31 | // construct nexts 32 | for i in 0..4 { 33 | let o = curarray[i]; 34 | curarray[i] = char::from_digit((o.to_digit(10).unwrap() + 1) % 10, 10).unwrap(); 35 | nexts.push(String::from_iter(curarray.iter())); 36 | 37 | curarray[i] = char::from_digit((o.to_digit(10).unwrap() + 9) % 10, 10).unwrap(); 38 | nexts.push(String::from_iter(curarray.iter())); 39 | curarray[i] = o; 40 | } 41 | 42 | for next in nexts.into_iter() { 43 | if !visited.contains_key(&next) && !deadset.contains(&next) { 44 | if next == target { 45 | return visited[&curs] + 1; 46 | } 47 | // q own next, visited need have a copy of next 48 | visited.insert(next.clone(), visited[&curs] + 1); 49 | // push next into q last, because we need to move ownership 50 | // of next into q 51 | q.push_back(next); 52 | } 53 | } 54 | } 55 | 56 | -1 57 | } 58 | } 59 | 60 | fn main() { 61 | println!("Hello, world!"); 62 | } 63 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/04-Water-Puzzle-Uncompleted/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/04-Water-Puzzle-Uncompleted/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/04-Water-Puzzle-Uncompleted/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::LinkedList; 2 | 3 | struct WaterPuzzle; 4 | 5 | impl WaterPuzzle { 6 | fn new(bottle1: usize, bottle2: usize) -> Self { 7 | // maximum of two bottles should less than 10 8 | assert!(bottle1 < 10); 9 | assert!(bottle2 < 10); 10 | 11 | let mut q = LinkedList::new(); 12 | let mut visited = vec![false; 100]; 13 | 14 | q.push_back(0usize); 15 | visited[0] = true; 16 | 17 | while !q.is_empty() { 18 | let cur = q.pop_front().unwrap(); 19 | let a = cur / 10; 20 | let b = cur % 10; 21 | 22 | let mut nexts = Vec::::new(); 23 | 24 | for next in nexts { 25 | if !visited[next] { 26 | q.push_back(next); 27 | visited[next] = true; 28 | } 29 | if next / 10 == 4 || next % 10 == 4 { 30 | return Self {}; 31 | } 32 | } 33 | } 34 | 35 | Self {} 36 | } 37 | } 38 | 39 | fn main() { 40 | println!("Hello, world!"); 41 | } 42 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/05-Water-Puzzle-Completed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-05" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/05-Water-Puzzle-Completed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-05" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/05-Water-Puzzle-Completed/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::LinkedList, ops::Index}; 2 | 3 | struct WaterPuzzle { 4 | end: i32, 5 | pre: Vec, 6 | } 7 | 8 | impl WaterPuzzle { 9 | fn new(bottle1: usize, bottle2: usize) -> Self { 10 | // maximum of two bottles should less than 10 11 | assert!(bottle1 < 10); 12 | assert!(bottle2 < 10); 13 | 14 | let mut q = LinkedList::new(); 15 | let mut visited = vec![false; 100]; 16 | let mut pre = vec![-1; 100]; 17 | 18 | q.push_back(0usize); 19 | visited[0] = true; 20 | 21 | while !q.is_empty() { 22 | let cur = q.pop_front().unwrap(); 23 | let a = cur / 10; 24 | let b = cur % 10; 25 | 26 | let mut nexts = Vec::::with_capacity(6); 27 | nexts.push(bottle1 * 10 + b); 28 | nexts.push(a * 10 + bottle2); 29 | nexts.push(b); 30 | nexts.push(a * 10); 31 | 32 | let x = usize::min(a, bottle2 - b); 33 | nexts.push((a - x) * 10 + (b + x)); 34 | 35 | let y = usize::min(b, bottle1 - a); 36 | nexts.push((a + y) * 10 + (b - y)); 37 | 38 | for next in nexts { 39 | if !visited[next] { 40 | q.push_back(next); 41 | visited[next] = true; 42 | pre[next] = cur as i32; 43 | } 44 | if next / 10 == 4 || next % 10 == 4 { 45 | return Self { 46 | end: next as i32, 47 | pre, 48 | }; 49 | } 50 | } 51 | } 52 | 53 | Self { 54 | end: -1, 55 | pre: vec![], 56 | } 57 | } 58 | 59 | fn result(&self) -> Box> { 60 | let mut res = Vec::new(); 61 | let mut cur = self.end; 62 | 63 | if cur == -1 { 64 | return Box::new(res.into_iter()); 65 | } 66 | 67 | while cur != 0 { 68 | res.push(cur as usize); 69 | cur = self.pre[cur as usize]; 70 | } 71 | res.push(0); 72 | res.reverse(); 73 | Box::new(res.into_iter()) 74 | } 75 | } 76 | 77 | fn main() { 78 | let water = WaterPuzzle::new(5, 3); 79 | water.result().for_each(|x| print!("{:02} ", x)); 80 | println!(); 81 | } 82 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/06-Sliding-Puzzle-Uncompleted/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-06" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/06-Sliding-Puzzle-Uncompleted/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-06" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/06-Sliding-Puzzle-Uncompleted/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, LinkedList}; 2 | 3 | // Leetcode 773, unfinished 4 | // use 6-bit number to present state 5 | struct Solution; 6 | 7 | impl Solution { 8 | pub fn sliding_puzzle(board: Vec>) -> i32 { 9 | let mut q = LinkedList::new(); 10 | let mut visited = HashMap::new(); 11 | 12 | let s0 = Solution::to_state(board); 13 | q.push_back(s0); 14 | visited.insert(s0, 0); 15 | if s0 == 123450 { 16 | return 0; 17 | } 18 | 19 | // while !q.is_empty() { 20 | // let s = q.pop_front().unwrap(); 21 | // } 22 | while let Some(s) = q.pop_front() { 23 | let nexts = Solution::get_nexts(s); 24 | 25 | for next in &nexts { 26 | if !visited.contains_key(next) { 27 | visited.insert(*next, visited[&s] + 1); 28 | q.push_back(*next); 29 | if *next == 123450 { 30 | return visited[next]; 31 | } 32 | } 33 | } 34 | } 35 | 36 | -1 37 | } 38 | 39 | fn to_state(board: Vec>) -> usize { 40 | let mut res = 0; 41 | for row in &board { 42 | for j in row { 43 | res = res * 10 + j; 44 | } 45 | } 46 | res as usize 47 | } 48 | 49 | fn get_nexts(s: usize) -> Vec { 50 | todo!() 51 | } 52 | } 53 | 54 | fn main() { 55 | println!("Hello, world!"); 56 | } 57 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/07-Sliding-Puzzle-Completed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter07-07" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/07-Sliding-Puzzle-Completed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter07-07" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /07-AI-Search-and-BFS/07-Sliding-Puzzle-Completed/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, LinkedList}; 2 | 3 | // Leetcode 773, finished 4 | // use 6-bit number to present state 5 | struct Solution; 6 | 7 | impl Solution { 8 | pub fn sliding_puzzle(board: Vec>) -> i32 { 9 | let mut q = LinkedList::new(); 10 | let mut visited = HashMap::new(); 11 | 12 | let s0 = Solution::to_state(&board); 13 | q.push_back(s0); 14 | visited.insert(s0, 0); 15 | if s0 == 123450 { 16 | return 0; 17 | } 18 | 19 | // while !q.is_empty() { 20 | // let s = q.pop_front().unwrap(); 21 | // } 22 | while let Some(s) = q.pop_front() { 23 | let nexts = Solution::get_nexts(s); 24 | for next in &nexts { 25 | if !visited.contains_key(next) { 26 | visited.insert(*next, visited[&s] + 1); 27 | q.push_back(*next); 28 | if *next == 123450 { 29 | return visited[next]; 30 | } 31 | } 32 | } 33 | } 34 | 35 | -1 36 | } 37 | 38 | fn to_state(board: &Vec>) -> usize { 39 | let mut res = 0; 40 | for row in board { 41 | for j in row { 42 | res = res * 10 + j; 43 | } 44 | } 45 | res as usize 46 | } 47 | 48 | fn to_board(mut s: i32) -> Vec> { 49 | let mut res = vec![vec![0; 3]; 2]; 50 | for i in (0..2).rev() { 51 | for j in (0..3).rev() { 52 | res[i][j] = s % 10; 53 | s /= 10; 54 | } 55 | } 56 | res 57 | } 58 | 59 | fn get_nexts(s: usize) -> Vec { 60 | let dirs = vec![vec![1, 0], vec![0, 1], vec![-1, 0], vec![0, -1]]; 61 | let in_area = |x, y| (0..2).contains(&x) && (0..3).contains(&y); 62 | let mut board = Solution::to_board(s as i32); 63 | 64 | // find zero 65 | let mut x = 0; 66 | let mut y = 0; 67 | for (i, row) in board.iter().enumerate() { 68 | for (j, e) in row.iter().enumerate() { 69 | if *e == 0 { 70 | x = i; 71 | y = j; 72 | } 73 | } 74 | } 75 | 76 | let mut res = Vec::new(); 77 | for dir in &dirs { 78 | let nextx = x + dir[0] as usize; 79 | let nexty = y + dir[1] as usize; 80 | if in_area(nextx, nexty) { 81 | let t = board[x][y]; 82 | board[x][y] = board[nextx][nexty]; 83 | board[nextx][nexty] = t; 84 | res.push(Solution::to_state(&board)); 85 | let t = board[x][y]; 86 | board[x][y] = board[nextx][nexty]; 87 | board[nextx][nexty] = t; 88 | } 89 | } 90 | 91 | res 92 | } 93 | } 94 | 95 | fn main() { 96 | println!("Hello, world!"); 97 | } 98 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter08-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter08-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 0 1 3 | 0 2 4 | 1 3 5 | 2 3 6 | 3 5 7 | 4 5 8 | 4 6 9 | 5 6 10 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/g2.txt: -------------------------------------------------------------------------------- 1 | 12 16 2 | 0 1 3 | 0 2 4 | 1 3 5 | 2 3 6 | 3 5 7 | 4 5 8 | 4 6 9 | 4 7 10 | 5 6 11 | 6 8 12 | 8 9 13 | 8 10 14 | 8 11 15 | 9 10 16 | 9 11 17 | 10 11 18 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/g3.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 0 1 3 | 0 2 4 | 1 2 5 | 1 3 6 | 2 3 7 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/src/edge.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | #[derive(Clone, Copy)] 4 | pub struct Edge { 5 | v: usize, 6 | w: usize, 7 | } 8 | 9 | impl Edge { 10 | pub fn new(v: usize, w: usize) -> Self { 11 | Self { v, w } 12 | } 13 | } 14 | 15 | impl Debug for Edge { 16 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 | write!(f, "{}-{}", self.v, self.w) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/src/find_bridges.rs: -------------------------------------------------------------------------------- 1 | use crate::{edge::Edge, graph::Graph}; 2 | 3 | /// # Interface of find bridges 4 | /// 5 | /// Must provide a special `fn bridges()` to achieve bridges of one graph 6 | pub trait FindBridges { 7 | fn bridges(&mut self) -> Vec; 8 | } 9 | pub struct FindBridgesImpl { 10 | g: Graph, 11 | visited: Vec, 12 | ord: Vec, 13 | low: Vec, 14 | cnt: usize, 15 | res: Vec, 16 | calculated: bool, 17 | } 18 | 19 | impl FindBridgesImpl { 20 | pub fn new(g: Graph) -> Self { 21 | let v = g.v(); 22 | Self { 23 | g, 24 | visited: vec![false; v], 25 | ord: vec![0; v], 26 | low: vec![0; v], 27 | cnt: 0, 28 | res: vec![], 29 | calculated: false, 30 | } 31 | } 32 | 33 | fn dfs(&mut self, v: usize, parent: usize) { 34 | self.visited[v] = true; 35 | self.ord[v] = self.cnt; 36 | self.low[v] = self.cnt; 37 | self.cnt += 1; 38 | 39 | for w in self.g.adj_edge(v) { 40 | if !self.visited[w] { 41 | self.dfs(w, v); 42 | self.low[v] = usize::min(self.low[v], self.low[w]); 43 | if self.low[w] > self.ord[v] { 44 | // find a bridge 45 | self.res.push(Edge::new(v, w)); 46 | } 47 | } else if w != parent { 48 | self.low[v] = usize::min(self.low[v], self.low[w]); 49 | } 50 | } 51 | } 52 | } 53 | 54 | impl FindBridges for FindBridgesImpl { 55 | fn bridges(&mut self) -> Vec { 56 | if !self.calculated { 57 | for w in 0..self.g.v() { 58 | if !self.visited[w] { 59 | self.dfs(w, w); 60 | } 61 | } 62 | self.calculated = true; 63 | } 64 | 65 | self.res.clone() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use find_bridges::{FindBridges, FindBridgesImpl}; 2 | use graph::Graph; 3 | 4 | mod edge; 5 | mod find_bridges; 6 | mod graph; 7 | 8 | fn main() { 9 | let g = Graph::from_file("g.txt"); 10 | let g2 = Graph::from_file("g2.txt"); 11 | let g3 = Graph::from_file("g3.txt"); 12 | let tree = Graph::from_file("tree.txt"); 13 | 14 | let mut fb = FindBridgesImpl::new(g); 15 | let mut fb2 = FindBridgesImpl::new(g2); 16 | let mut fb3 = FindBridgesImpl::new(g3); 17 | let mut fb_tree = FindBridgesImpl::new(tree); 18 | 19 | println!("Bridges in g: {:?}", fb.bridges()); 20 | println!("Bridges in g1: {:?}", fb2.bridges()); 21 | println!("Bridges in g2: {:?}", fb3.bridges()); 22 | println!("Bridges in tree: {:?}", fb_tree.bridges()); 23 | } 24 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/04-Bridges-Algorithm/tree.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 3 4 | 1 6 5 | 2 3 6 | 2 5 7 | 3 4 8 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter08-07" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter08-07" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 0 1 3 | 0 2 4 | 1 3 5 | 2 3 6 | 3 5 7 | 4 5 8 | 4 6 9 | 5 6 10 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/g2.txt: -------------------------------------------------------------------------------- 1 | 12 16 2 | 0 1 3 | 0 2 4 | 1 3 5 | 2 3 6 | 3 5 7 | 4 5 8 | 4 6 9 | 4 7 10 | 5 6 11 | 6 8 12 | 8 9 13 | 8 10 14 | 8 11 15 | 9 10 16 | 9 11 17 | 10 11 18 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/g3.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 0 1 3 | 0 2 4 | 1 2 5 | 1 3 6 | 2 3 7 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/src/edge.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | #[derive(Clone, Copy)] 4 | pub struct Edge { 5 | v: usize, 6 | w: usize, 7 | } 8 | 9 | impl Edge { 10 | pub fn new(v: usize, w: usize) -> Self { 11 | Self { v, w } 12 | } 13 | } 14 | 15 | impl Debug for Edge { 16 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 | write!(f, "{}-{}", self.v, self.w) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/src/find_bridges.rs: -------------------------------------------------------------------------------- 1 | use crate::{edge::Edge, graph::Graph}; 2 | 3 | /// # Interface of find bridges 4 | /// 5 | /// Must provide a special `fn bridges()` to achieve bridges of one graph 6 | pub trait FindBridges { 7 | fn bridges(&mut self) -> Vec; 8 | } 9 | 10 | pub struct FindBridgesImpl { 11 | g: Graph, 12 | visited: Vec, 13 | ord: Vec, 14 | low: Vec, 15 | cnt: usize, 16 | res: Vec, 17 | calculated: bool, 18 | } 19 | 20 | impl FindBridgesImpl { 21 | pub fn new(g: Graph) -> Self { 22 | let v = g.v(); 23 | Self { 24 | g, 25 | visited: vec![false; v], 26 | ord: vec![0; v], 27 | low: vec![0; v], 28 | cnt: 0, 29 | res: vec![], 30 | calculated: false, 31 | } 32 | } 33 | 34 | fn dfs(&mut self, v: usize, parent: usize) { 35 | self.visited[v] = true; 36 | self.ord[v] = self.cnt; 37 | self.low[v] = self.cnt; 38 | self.cnt += 1; 39 | 40 | for w in self.g.adj_edge(v) { 41 | if !self.visited[w] { 42 | self.dfs(w, v); 43 | self.low[v] = usize::min(self.low[v], self.low[w]); 44 | if self.low[w] > self.ord[v] { 45 | // find a bridge 46 | self.res.push(Edge::new(v, w)); 47 | } 48 | } else if w != parent { 49 | self.low[v] = usize::min(self.low[v], self.low[w]); 50 | } 51 | } 52 | } 53 | } 54 | 55 | impl FindBridges for FindBridgesImpl { 56 | fn bridges(&mut self) -> Vec { 57 | if !self.calculated { 58 | for w in 0..self.g.v() { 59 | if !self.visited[w] { 60 | self.dfs(w, w); 61 | } 62 | } 63 | self.calculated = true; 64 | } 65 | 66 | self.res.clone() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/src/find_cut_points.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use crate::graph::Graph; 4 | 5 | /// # Interface of find cur points 6 | /// 7 | /// Must provide a special `fn bridges()` to achieve bridges of one graph 8 | pub trait FindCutPoints { 9 | fn cut_points(&mut self) -> Vec; 10 | } 11 | 12 | pub struct FindCutPointsImpl { 13 | g: Graph, 14 | visited: Vec, 15 | ord: Vec, 16 | low: Vec, 17 | cnt: usize, 18 | res: HashSet, 19 | calculated: bool, 20 | } 21 | 22 | impl FindCutPointsImpl { 23 | pub fn new(g: Graph) -> Self { 24 | let v = g.v(); 25 | Self { 26 | g, 27 | visited: vec![false; v], 28 | ord: vec![0; v], 29 | low: vec![0; v], 30 | cnt: 0, 31 | res: HashSet::new(), 32 | calculated: false, 33 | } 34 | } 35 | 36 | fn dfs(&mut self, v: usize, parent: usize) { 37 | self.visited[v] = true; 38 | self.ord[v] = self.cnt; 39 | self.low[v] = self.cnt; 40 | self.cnt += 1; 41 | 42 | let mut child = 0; 43 | for w in self.g.adj_edge(v) { 44 | if !self.visited[w] { 45 | self.dfs(w, v); 46 | self.low[v] = usize::min(self.low[v], self.low[w]); 47 | if v != parent && self.low[w] >= self.ord[v] { 48 | self.res.insert(v); 49 | } 50 | child += 1; 51 | if v == parent && child > 1 { 52 | self.res.insert(v); 53 | } 54 | } else if w != parent { 55 | self.low[v] = usize::min(self.low[v], self.low[w]); 56 | } 57 | } 58 | } 59 | } 60 | 61 | impl FindCutPoints for FindCutPointsImpl { 62 | fn cut_points(&mut self) -> Vec { 63 | if !self.calculated { 64 | for w in 0..self.g.v() { 65 | if !self.visited[w] { 66 | self.dfs(w, w); 67 | } 68 | } 69 | self.calculated = true; 70 | } 71 | 72 | self.res.clone().into_iter().collect() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use find_bridges::{FindBridges, FindBridgesImpl}; 2 | use find_cut_points::{FindCutPoints, FindCutPointsImpl}; 3 | use graph::Graph; 4 | 5 | mod edge; 6 | mod find_bridges; 7 | mod find_cut_points; 8 | mod graph; 9 | 10 | fn main() { 11 | let g = Graph::from_file("g.txt"); 12 | let g2 = Graph::from_file("g2.txt"); 13 | let g3 = Graph::from_file("g3.txt"); 14 | let tree = Graph::from_file("tree.txt"); 15 | 16 | let mut fc = FindCutPointsImpl::new(g); 17 | let mut fc2 = FindCutPointsImpl::new(g2); 18 | let mut fc3 = FindCutPointsImpl::new(g3); 19 | let mut fc_tree = FindCutPointsImpl::new(tree); 20 | 21 | println!("Bridges in g: {:?}", fc.cut_points()); 22 | println!("Bridges in g1: {:?}", fc2.cut_points()); 23 | println!("Bridges in g2: {:?}", fc3.cut_points()); 24 | println!("Bridges in tree: {:?}", fc_tree.cut_points()); 25 | } 26 | -------------------------------------------------------------------------------- /08-Bridges-and-Cut-Points/07-Cut-Points-Algorithm/tree.txt: -------------------------------------------------------------------------------- 1 | 7 6 2 | 0 1 3 | 0 3 4 | 1 6 5 | 2 3 6 | 2 5 7 | 3 4 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter09-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter09-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/g.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 0 1 3 | 0 2 4 | 0 3 5 | 1 2 6 | 1 3 7 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/g2.txt: -------------------------------------------------------------------------------- 1 | 20 30 2 | 0 1 3 | 0 4 4 | 0 13 5 | 1 2 6 | 1 11 7 | 2 9 8 | 2 3 9 | 3 4 10 | 3 7 11 | 4 5 12 | 5 6 13 | 5 14 14 | 6 7 15 | 6 16 16 | 7 8 17 | 8 9 18 | 8 17 19 | 9 10 20 | 10 11 21 | 10 18 22 | 11 12 23 | 12 13 24 | 12 19 25 | 13 14 26 | 14 15 27 | 15 16 28 | 15 19 29 | 16 17 30 | 17 18 31 | 18 19 32 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/src/hamilton_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub trait HamiltonLoop { 4 | fn hamilton_loop(&mut self) -> Vec; 5 | } 6 | 7 | pub struct HamiltonLoopImpl { 8 | g: Graph, 9 | visited: Vec, 10 | pre: Vec, 11 | end: Option, 12 | } 13 | 14 | impl HamiltonLoopImpl { 15 | pub fn new(g: Graph) -> Self { 16 | let v = g.v(); 17 | let mut hl = Self { 18 | g, 19 | visited: vec![false; v], 20 | pre: vec![0; v], 21 | end: None, 22 | }; 23 | hl.dfs(0, 0); 24 | hl 25 | } 26 | 27 | fn dfs(&mut self, v: usize, parent: usize) -> bool { 28 | self.visited[v] = true; 29 | self.pre[v] = parent; 30 | 31 | for w in self.g.adj_edge(v) { 32 | if !self.visited[w] { 33 | if self.dfs(w, v) { 34 | return true; 35 | } 36 | } else if w == 0 && self.all_visited() { 37 | self.end = Some(v); 38 | return true; 39 | } 40 | } 41 | 42 | self.visited[v] = false; 43 | false 44 | } 45 | 46 | fn all_visited(&self) -> bool { 47 | for v in self.visited.iter() { 48 | if !v { 49 | return false; 50 | } 51 | } 52 | true 53 | } 54 | } 55 | 56 | impl HamiltonLoop for HamiltonLoopImpl { 57 | fn hamilton_loop(&mut self) -> Vec { 58 | if let Some(mut end) = self.end { 59 | // find a loop 60 | let mut res = Vec::with_capacity(self.g.v()); 61 | while end != 0 { 62 | res.push(end); 63 | end = self.pre[end]; 64 | } 65 | res.push(0); 66 | res.reverse(); 67 | res 68 | } else { 69 | vec![] 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/03-Hamilton-Loop/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use hamilton_loop::{HamiltonLoop, HamiltonLoopImpl}; 3 | 4 | mod graph; 5 | mod hamilton_loop; 6 | 7 | fn main() { 8 | let g = Graph::from_file("g.txt"); 9 | let mut hl = HamiltonLoopImpl::new(g); 10 | println!("{:?}", hl.hamilton_loop()); 11 | 12 | let g2 = Graph::from_file("g2.txt"); 13 | let mut hl2 = HamiltonLoopImpl::new(g2); 14 | println!("{:?}", hl2.hamilton_loop()); 15 | } 16 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter09-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter09-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/g.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 0 1 3 | 0 2 4 | 0 3 5 | 1 2 6 | 1 3 7 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/g2.txt: -------------------------------------------------------------------------------- 1 | 20 30 2 | 0 1 3 | 0 4 4 | 0 13 5 | 1 2 6 | 1 11 7 | 2 9 8 | 2 3 9 | 3 4 10 | 3 7 11 | 4 5 12 | 5 6 13 | 5 14 14 | 6 7 15 | 6 16 16 | 7 8 17 | 8 9 18 | 8 17 19 | 9 10 20 | 10 11 21 | 10 18 22 | 11 12 23 | 12 13 24 | 12 19 25 | 13 14 26 | 14 15 27 | 15 16 28 | 15 19 29 | 16 17 30 | 17 18 31 | 18 19 32 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/src/hamilton_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub trait HamiltonLoop { 4 | fn hamilton_loop(&mut self) -> Vec; 5 | } 6 | 7 | pub struct HamiltonLoopImpl { 8 | g: Graph, 9 | visited: Vec, 10 | pre: Vec, 11 | end: Option, 12 | } 13 | 14 | impl HamiltonLoopImpl { 15 | pub fn new(g: Graph) -> Self { 16 | let v = g.v(); 17 | let mut hl = Self { 18 | g, 19 | visited: vec![false; v], 20 | pre: vec![0; v], 21 | end: None, 22 | }; 23 | hl.dfs(0, 0, v); 24 | hl 25 | } 26 | 27 | fn dfs(&mut self, v: usize, parent: usize, left: usize) -> bool { 28 | self.visited[v] = true; 29 | self.pre[v] = parent; 30 | if left == 1 && self.g.has_edge(v, 0) { 31 | // v is the last one to visit 32 | self.end = Some(v); 33 | return true; 34 | } 35 | 36 | for w in self.g.adj_edge(v) { 37 | if !self.visited[w] && self.dfs(w, v, left - 1) { 38 | return true; 39 | } 40 | } 41 | 42 | self.visited[v] = false; 43 | false 44 | } 45 | } 46 | 47 | impl HamiltonLoop for HamiltonLoopImpl { 48 | fn hamilton_loop(&mut self) -> Vec { 49 | if let Some(mut end) = self.end { 50 | // find a loop 51 | let mut res = Vec::with_capacity(self.g.v()); 52 | while end != 0 { 53 | res.push(end); 54 | end = self.pre[end]; 55 | } 56 | res.push(0); 57 | res.reverse(); 58 | res 59 | } else { 60 | vec![] 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/04-Hamilton-Loop-Optimization/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use graph::Graph; 6 | use hamilton_loop::{HamiltonLoop, HamiltonLoopImpl}; 7 | 8 | mod graph; 9 | mod hamilton_loop; 10 | 11 | fn main() { 12 | let g = Graph::from_file("g.txt"); 13 | let mut hl = HamiltonLoopImpl::new(g); 14 | println!("{:?}", hl.hamilton_loop()); 15 | 16 | let g2 = Graph::from_file("g2.txt"); 17 | let mut hl2 = HamiltonLoopImpl::new(g2); 18 | println!("{:?}", hl2.hamilton_loop()); 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use crate::*; 24 | use test::Bencher; 25 | 26 | #[bench] 27 | fn test(b: &mut Bencher) { 28 | b.iter(|| main()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/06-Unique-Paths-III/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter09-06" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/06-Unique-Paths-III/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter09-06" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/06-Unique-Paths-III/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Solution; 2 | 3 | const DIR: [[i32; 2]; 4] = [[-1, 0], [0, -1], [1, 0], [0, 1]]; 4 | static mut R: usize = 0; 5 | static mut C: usize = 0; 6 | static mut END: usize = 0; 7 | 8 | impl Solution { 9 | pub fn unique_paths_iii(mut grid: Vec>) -> i32 { 10 | let r; 11 | let c; 12 | unsafe { 13 | R = grid.len(); 14 | C = grid[0].len(); 15 | r = R; 16 | c = C; 17 | } 18 | let mut start = 0; 19 | let mut visited = vec![vec![false; c]; r]; 20 | let mut left = r * c; 21 | 22 | for i in 0..r { 23 | for j in 0..c { 24 | if grid[i][j] == 1 { 25 | start = i * c + j; 26 | grid[i][j] = 0; 27 | } else if grid[i][j] == 2 { 28 | unsafe { 29 | END = i * c + j; 30 | } 31 | grid[i][j] = 0; 32 | } else if grid[i][j] == -1 { 33 | left -= 1; 34 | } 35 | } 36 | } 37 | 38 | Solution::dfs(start, left, &mut visited, &mut grid) 39 | } 40 | 41 | fn dfs(start: usize, left: usize, visited: &mut [Vec], grid: &mut [Vec]) -> i32 { 42 | unsafe { 43 | let x = start / C; 44 | let y = start % C; 45 | visited[x][y] = true; 46 | if left == 1 && start == END { 47 | visited[x][y] = false; 48 | return 1; 49 | } 50 | 51 | let in_area = |x, y| -> bool { x >= 0 && x < R as i32 && y >= 0 && y < C as i32 }; 52 | 53 | let mut res = 0; 54 | for dir in DIR { 55 | let nextx = x as i32 + dir[0]; 56 | let nexty = y as i32 + dir[1]; 57 | if in_area(nextx, nexty) 58 | && !visited[nextx as usize][nexty as usize] 59 | && grid[nextx as usize][nexty as usize] != -1 60 | { 61 | res += 62 | Solution::dfs((nextx * C as i32 + nexty) as usize, left - 1, visited, grid); 63 | } 64 | } 65 | 66 | visited[x][y] = false; 67 | res 68 | } 69 | } 70 | } 71 | 72 | fn main() { 73 | println!("Hello, world!"); 74 | } 75 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/08-State-Compression/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter09-08" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/08-State-Compression/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter09-08" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/08-State-Compression/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Solution; 2 | 3 | const DIR: [[i32; 2]; 4] = [[-1, 0], [0, -1], [1, 0], [0, 1]]; 4 | static mut R: usize = 0; 5 | static mut C: usize = 0; 6 | static mut END: usize = 0; 7 | 8 | impl Solution { 9 | pub fn unique_paths_iii(mut grid: Vec>) -> i32 { 10 | let r; 11 | let c; 12 | unsafe { 13 | R = grid.len(); 14 | C = grid[0].len(); 15 | r = R; 16 | c = C; 17 | } 18 | let mut start = 0; 19 | let mut left = r * c; 20 | 21 | for i in 0..r { 22 | for j in 0..c { 23 | if grid[i][j] == 1 { 24 | start = i * c + j; 25 | grid[i][j] = 0; 26 | } else if grid[i][j] == 2 { 27 | unsafe { 28 | END = i * c + j; 29 | } 30 | grid[i][j] = 0; 31 | } else if grid[i][j] == -1 { 32 | left -= 1; 33 | } 34 | } 35 | } 36 | 37 | Solution::dfs(start, left, 0, &mut grid) 38 | } 39 | 40 | fn dfs(start: usize, left: usize, mut visited: usize, grid: &mut [Vec]) -> i32 { 41 | unsafe { 42 | let x = start / C; 43 | let y = start % C; 44 | visited |= 1 << start; 45 | if left == 1 && start == END { 46 | return 1; 47 | } 48 | 49 | let in_area = |x, y| -> bool { x >= 0 && x < R as i32 && y >= 0 && y < C as i32 }; 50 | 51 | let mut res = 0; 52 | for dir in DIR { 53 | let nextx = x as i32 + dir[0]; 54 | let nexty = y as i32 + dir[1]; 55 | let next = nextx * C as i32 + nexty; 56 | if in_area(nextx, nexty) 57 | && (visited & (1 << next)) == 0 58 | && grid[nextx as usize][nexty as usize] != -1 59 | { 60 | res += Solution::dfs(next as usize, left - 1, visited, grid); 61 | } 62 | } 63 | 64 | res 65 | } 66 | } 67 | } 68 | 69 | fn main() { 70 | println!("Hello, world!"); 71 | } 72 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/09-Memory-Search/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter09-09" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/09-Memory-Search/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter09-09" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /09-Hamilton-Loop-and-Path/09-Memory-Search/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Solution; 2 | 3 | const DIR: [[i32; 2]; 4] = [[-1, 0], [0, -1], [1, 0], [0, 1]]; 4 | static mut R: usize = 0; 5 | static mut C: usize = 0; 6 | static mut END: usize = 0; 7 | 8 | impl Solution { 9 | pub fn unique_paths_iii(mut grid: Vec>) -> i32 { 10 | let r; 11 | let c; 12 | unsafe { 13 | R = grid.len(); 14 | C = grid[0].len(); 15 | r = R; 16 | c = C; 17 | } 18 | let mut start = 0; 19 | let mut left = r * c; 20 | let mut memo = vec![vec![-1; c * r]; 1 << (c * r)]; 21 | 22 | for i in 0..r { 23 | for j in 0..c { 24 | if grid[i][j] == 1 { 25 | start = i * c + j; 26 | grid[i][j] = 0; 27 | } else if grid[i][j] == 2 { 28 | unsafe { 29 | END = i * c + j; 30 | } 31 | grid[i][j] = 0; 32 | } else if grid[i][j] == -1 { 33 | left -= 1; 34 | } 35 | } 36 | } 37 | 38 | Solution::dfs(start, left, 0, &mut grid, &mut memo) 39 | } 40 | 41 | fn dfs( 42 | start: usize, 43 | left: usize, 44 | mut visited: usize, 45 | grid: &mut [Vec], 46 | memo: &mut [Vec], 47 | ) -> i32 { 48 | unsafe { 49 | if memo[visited][start] != -1 { 50 | return memo[visited][start]; 51 | } 52 | let x = start / C; 53 | let y = start % C; 54 | visited |= 1 << start; 55 | if left == 1 && start == END { 56 | visited &= !(1 << start); 57 | memo[visited][start] = 1; 58 | return 1; 59 | } 60 | 61 | let in_area = |x, y| -> bool { x >= 0 && x < R as i32 && y >= 0 && y < C as i32 }; 62 | 63 | let mut res = 0; 64 | for dir in DIR { 65 | let nextx = x as i32 + dir[0]; 66 | let nexty = y as i32 + dir[1]; 67 | let next = nextx * C as i32 + nexty; 68 | if in_area(nextx, nexty) 69 | && (visited & (1 << next)) == 0 70 | && grid[nextx as usize][nexty as usize] != -1 71 | { 72 | res += Solution::dfs(next as usize, left - 1, visited, grid, memo); 73 | } 74 | } 75 | 76 | visited &= !(1 << start); 77 | memo[visited][start] = res; 78 | res 79 | } 80 | } 81 | } 82 | 83 | fn main() { 84 | println!("Hello, world!"); 85 | } 86 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/03-Euler-Loop-Detection/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter10-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/03-Euler-Loop-Detection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter10-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/03-Euler-Loop-Detection/src/euler_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | trait EulerLoop { 4 | fn has_loop(&self) -> bool; 5 | } 6 | 7 | struct EulerLoopImpl { 8 | g: Graph, 9 | } 10 | 11 | impl EulerLoopImpl { 12 | fn new(g: Graph) -> Self { 13 | Self { g } 14 | } 15 | 16 | fn dfs(&self, visited: &mut Vec, v: usize) { 17 | visited[v] = true; 18 | for w in self.g.adj_edge(v) { 19 | if !visited[w] { 20 | self.dfs(visited, w); 21 | } 22 | } 23 | } 24 | } 25 | 26 | impl EulerLoop for EulerLoopImpl { 27 | fn has_loop(&self) -> bool { 28 | // check CC 29 | let mut visited = vec![false; self.g.v()]; 30 | self.dfs(&mut visited, 0); 31 | for v in visited { 32 | if !v { 33 | return false; // not CC 34 | } 35 | } 36 | 37 | for v in 0..self.g.v() { 38 | if self.g.degree(v) % 2 != 0 { 39 | return false; // odd degree 40 | } 41 | } 42 | 43 | true 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/03-Euler-Loop-Detection/src/main.rs: -------------------------------------------------------------------------------- 1 | mod euler_loop; 2 | mod graph; 3 | 4 | fn main() {} 5 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter10-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter10-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 5 6 2 | 0 1 3 | 0 2 4 | 1 2 5 | 2 3 6 | 2 4 7 | 3 4 8 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/g2.txt: -------------------------------------------------------------------------------- 1 | 11 15 2 | 0 1 3 | 0 3 4 | 1 2 5 | 1 4 6 | 1 5 7 | 2 5 8 | 3 4 9 | 4 5 10 | 4 6 11 | 5 7 12 | 6 7 13 | 7 8 14 | 7 9 15 | 8 10 16 | 9 10 17 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/src/euler_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub trait EulerLoop { 4 | fn has_loop(&self) -> bool; 5 | fn euler_loop(&self) -> Vec; 6 | } 7 | 8 | pub struct EulerLoopImpl { 9 | g: Graph, 10 | } 11 | 12 | impl EulerLoopImpl { 13 | pub fn new(g: Graph) -> Self { 14 | Self { g } 15 | } 16 | 17 | fn dfs(&self, visited: &mut Vec, v: usize) { 18 | visited[v] = true; 19 | for w in self.g.adj_edge(v) { 20 | if !visited[w] { 21 | self.dfs(visited, w); 22 | } 23 | } 24 | } 25 | } 26 | 27 | impl EulerLoop for EulerLoopImpl { 28 | fn has_loop(&self) -> bool { 29 | // check CC 30 | let mut visited = vec![false; self.g.v()]; 31 | self.dfs(&mut visited, 0); 32 | for v in visited { 33 | if !v { 34 | return false; // not CC 35 | } 36 | } 37 | 38 | for v in 0..self.g.v() { 39 | if self.g.degree(v) % 2 != 0 { 40 | return false; // odd degree 41 | } 42 | } 43 | 44 | true 45 | } 46 | 47 | fn euler_loop(&self) -> Vec { 48 | if !self.has_loop() { 49 | return vec![]; 50 | } 51 | 52 | let mut res = Vec::with_capacity(self.g.e() + 1); 53 | let mut g = self.g.clone(); 54 | let mut stack = vec![]; 55 | let mut curv = 0; 56 | // important, push curv first but this curv will not push into res 57 | stack.push(curv); 58 | while !stack.is_empty() { 59 | if g.degree(curv) != 0 { 60 | stack.push(curv); 61 | let w = g.adj_edge(curv).next().unwrap(); 62 | g.remove_edge(curv, w); 63 | curv = w; 64 | } else { 65 | res.push(curv); 66 | curv = stack.pop().unwrap(); 67 | } 68 | } 69 | 70 | res 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /10-Euler-Loop-and-Euler-Path/06-Hierholzer-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use euler_loop::EulerLoopImpl; 2 | use graph::Graph; 3 | 4 | use crate::euler_loop::EulerLoop; 5 | 6 | mod euler_loop; 7 | mod graph; 8 | 9 | fn main() { 10 | let g = Graph::from_file("g.txt"); 11 | let el = EulerLoopImpl::new(g); 12 | println!("{:?}", el.euler_loop()); 13 | 14 | let g2 = Graph::from_file("g2.txt"); 15 | let el2 = EulerLoopImpl::new(g2); 16 | println!("{:?}", el2.euler_loop()); 17 | } 18 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/01-Weighted-Graph/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-01" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/01-Weighted-Graph/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-01" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/01-Weighted-Graph/src/main.rs: -------------------------------------------------------------------------------- 1 | mod weighted_graph; 2 | 3 | fn main() { 4 | println!("Hello, world!"); 5 | } 6 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/02-Weighted-Graph-Completed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-02" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/02-Weighted-Graph-Completed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-02" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/02-Weighted-Graph-Completed/g.txt: -------------------------------------------------------------------------------- 1 | 7 12 2 | 0 1 2 3 | 0 3 7 4 | 0 5 2 5 | 1 2 1 6 | 1 3 4 7 | 1 4 3 8 | 1 5 5 9 | 2 4 4 10 | 2 5 4 11 | 3 4 1 12 | 3 6 5 13 | 4 6 7 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/02-Weighted-Graph-Completed/src/main.rs: -------------------------------------------------------------------------------- 1 | use weighted_graph::WeightedGraph; 2 | 3 | mod weighted_graph; 4 | 5 | fn main() { 6 | let g = WeightedGraph::from_file("g.txt"); 7 | println!("{g}"); 8 | } 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-05" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-05" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 7 12 2 | 0 1 2 3 | 0 3 7 4 | 0 5 2 5 | 1 2 1 6 | 1 3 4 7 | 1 4 3 8 | 1 5 5 9 | 2 4 4 10 | 2 5 4 11 | 3 4 1 12 | 3 6 5 13 | 4 6 7 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/src/cc.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Cc { 4 | g: WeightedGraph, 5 | visited: Vec, 6 | count: usize, 7 | } 8 | 9 | impl Cc { 10 | pub fn count(&mut self) -> usize { 11 | for v in 0..self.g.v() { 12 | if !self.visited[v] { 13 | self.dfs(v); 14 | self.count += 1; 15 | } 16 | } 17 | self.count 18 | } 19 | 20 | pub fn new(g: WeightedGraph) -> Self { 21 | let v = g.v(); 22 | Self { 23 | g, 24 | visited: vec![false; v], 25 | count: 0, 26 | } 27 | } 28 | 29 | fn dfs(&mut self, v: usize) { 30 | self.visited[v] = true; 31 | for w in self.g.adj_edge(v) { 32 | if !self.visited[w] { 33 | self.dfs(w); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/src/kruskal.rs: -------------------------------------------------------------------------------- 1 | use crate::cc::Cc; 2 | use crate::union_find::UnionFind; 3 | use crate::weighted_edge::WeightedEdge; 4 | use crate::weighted_graph::WeightedGraph; 5 | 6 | pub trait Kruskal { 7 | fn mst(&self) -> Vec; 8 | } 9 | 10 | pub struct KruskalImpl { 11 | g: WeightedGraph, 12 | } 13 | 14 | impl KruskalImpl { 15 | pub fn new(g: WeightedGraph) -> Self { 16 | Self { g } 17 | } 18 | } 19 | 20 | impl Kruskal for KruskalImpl { 21 | fn mst(&self) -> Vec { 22 | let mut cc = Cc::new(self.g.clone()); 23 | if cc.count() > 1 { 24 | return vec![]; 25 | } 26 | 27 | let mut edges = Vec::with_capacity(self.g.e()); 28 | for v in 0..self.g.v() { 29 | for w in self.g.adj_edge(v) { 30 | if v < w { 31 | edges.push(WeightedEdge::new(v, w, self.g.get_weight(v, w).unwrap())); 32 | } 33 | } 34 | } 35 | edges.sort_unstable_by_key(|a| a.weight()); 36 | 37 | let mut mst = Vec::with_capacity(self.g.v() + 1); 38 | let mut union_find = UnionFind::new(self.g.v()); 39 | for edge in edges { 40 | let v = edge.v(); 41 | let w = edge.w(); 42 | if !union_find.is_connected(v, w) { 43 | mst.push(edge); 44 | union_find.union(v, w); 45 | } 46 | } 47 | 48 | mst 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use kruskal::{Kruskal, KruskalImpl}; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod cc; 5 | mod kruskal; 6 | mod union_find; 7 | mod weighted_edge; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = WeightedGraph::from_file("g.txt"); 12 | let kruskal = KruskalImpl::new(g); 13 | println!("{:#?}", kruskal.mst()) 14 | } 15 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/src/union_find.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub struct UnionFind { 4 | parent: Vec, 5 | } 6 | 7 | impl UnionFind { 8 | pub fn new(n: usize) -> Self { 9 | let mut parent = Vec::with_capacity(n); 10 | for i in 0..n { 11 | parent.push(i); 12 | } 13 | 14 | Self { parent } 15 | } 16 | 17 | pub fn find(&mut self, p: usize) -> usize { 18 | if self.parent[p] != p { 19 | self.parent[p] = self.find(self.parent[p]); 20 | } 21 | self.parent[p] 22 | } 23 | 24 | pub fn is_connected(&mut self, p: usize, q: usize) -> bool { 25 | self.find(p) == self.find(q) 26 | } 27 | 28 | pub fn union(&mut self, p: usize, q: usize) { 29 | let l = self.find(p); 30 | let r = self.find(q); 31 | 32 | if l == r { 33 | return; 34 | } 35 | self.parent[l] = r; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/05-Kruskal-Algorithm/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | pub struct WeightedEdge { 6 | v: usize, 7 | w: usize, 8 | weight: i32, 9 | } 10 | 11 | impl WeightedEdge { 12 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 13 | Self { v, w, weight } 14 | } 15 | 16 | pub fn weight(&self) -> i32 { 17 | self.weight 18 | } 19 | 20 | pub fn w(&self) -> usize { 21 | self.w 22 | } 23 | 24 | pub fn v(&self) -> usize { 25 | self.v 26 | } 27 | } 28 | 29 | impl Debug for WeightedEdge { 30 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 31 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-05" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-05" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/g.txt: -------------------------------------------------------------------------------- 1 | 7 12 2 | 0 1 2 3 | 0 3 7 4 | 0 5 2 5 | 1 2 1 6 | 1 3 4 7 | 1 4 3 8 | 1 5 5 9 | 2 4 4 10 | 2 5 4 11 | 3 4 1 12 | 3 6 5 13 | 4 6 7 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/src/cc.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Cc { 4 | g: WeightedGraph, 5 | visited: Vec, 6 | count: usize, 7 | } 8 | 9 | impl Cc { 10 | pub fn count(&mut self) -> usize { 11 | for v in 0..self.g.v() { 12 | if !self.visited[v] { 13 | self.dfs(v); 14 | self.count += 1; 15 | } 16 | } 17 | self.count 18 | } 19 | 20 | pub fn new(g: WeightedGraph) -> Self { 21 | let v = g.v(); 22 | Self { 23 | g, 24 | visited: vec![false; v], 25 | count: 0, 26 | } 27 | } 28 | 29 | fn dfs(&mut self, v: usize) { 30 | self.visited[v] = true; 31 | for w in self.g.adj_edge(v) { 32 | if !self.visited[w] { 33 | self.dfs(w); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/src/kruskal.rs: -------------------------------------------------------------------------------- 1 | use crate::cc::Cc; 2 | use crate::union_find::UnionFind; 3 | use crate::weighted_edge::WeightedEdge; 4 | use crate::weighted_graph::WeightedGraph; 5 | 6 | pub trait Kruskal { 7 | fn mst(&self) -> Vec; 8 | } 9 | 10 | pub struct KruskalImpl { 11 | g: WeightedGraph, 12 | } 13 | 14 | impl KruskalImpl { 15 | pub fn new(g: WeightedGraph) -> Self { 16 | Self { g } 17 | } 18 | } 19 | 20 | impl Kruskal for KruskalImpl { 21 | fn mst(&self) -> Vec { 22 | let mut cc = Cc::new(self.g.clone()); 23 | if cc.count() > 1 { 24 | return vec![]; 25 | } 26 | 27 | let mut edges = Vec::with_capacity(self.g.e()); 28 | for v in 0..self.g.v() { 29 | for w in self.g.adj_edge(v) { 30 | if v < w { 31 | edges.push(WeightedEdge::new(v, w, self.g.get_weight(v, w).unwrap())); 32 | } 33 | } 34 | } 35 | edges.sort_unstable_by_key(|a| a.weight()); 36 | 37 | let mut mst = Vec::with_capacity(self.g.v() + 1); 38 | let mut union_find = UnionFind::new(self.g.v()); 39 | for edge in edges { 40 | let v = edge.v(); 41 | let w = edge.w(); 42 | if !union_find.is_connected(v, w) { 43 | mst.push(edge); 44 | union_find.union(v, w); 45 | } 46 | } 47 | 48 | mst 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/src/main.rs: -------------------------------------------------------------------------------- 1 | use kruskal::{Kruskal, KruskalImpl}; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod cc; 5 | mod kruskal; 6 | mod union_find; 7 | mod weighted_edge; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = WeightedGraph::from_file("g.txt"); 12 | let kruskal = KruskalImpl::new(g); 13 | println!("{:#?}", kruskal.mst()) 14 | } 15 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/src/union_find.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub struct UnionFind { 4 | parent: Vec, 5 | } 6 | 7 | impl UnionFind { 8 | pub fn new(n: usize) -> Self { 9 | let mut parent = Vec::with_capacity(n); 10 | for i in 0..n { 11 | parent.push(i); 12 | } 13 | 14 | Self { parent } 15 | } 16 | 17 | pub fn find(&mut self, p: usize) -> usize { 18 | if self.parent[p] != p { 19 | self.parent[p] = self.find(self.parent[p]); 20 | } 21 | self.parent[p] 22 | } 23 | 24 | pub fn is_connected(&mut self, p: usize, q: usize) -> bool { 25 | self.find(p) == self.find(q) 26 | } 27 | 28 | pub fn union(&mut self, p: usize, q: usize) { 29 | let l = self.find(p); 30 | let r = self.find(q); 31 | 32 | if l == r { 33 | return; 34 | } 35 | self.parent[l] = r; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/06-Kruskal-Algorithm-Completed/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | pub struct WeightedEdge { 6 | v: usize, 7 | w: usize, 8 | weight: i32, 9 | } 10 | 11 | impl WeightedEdge { 12 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 13 | Self { v, w, weight } 14 | } 15 | 16 | pub fn weight(&self) -> i32 { 17 | self.weight 18 | } 19 | 20 | pub fn w(&self) -> usize { 21 | self.w 22 | } 23 | 24 | pub fn v(&self) -> usize { 25 | self.v 26 | } 27 | } 28 | 29 | impl Debug for WeightedEdge { 30 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 31 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-08" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-08" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 7 12 2 | 0 1 2 3 | 0 3 7 4 | 0 5 2 5 | 1 2 1 6 | 1 3 4 7 | 1 4 3 8 | 1 5 5 9 | 2 4 4 10 | 2 5 4 11 | 3 4 1 12 | 3 6 5 13 | 4 6 7 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/src/cc.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Cc { 4 | g: WeightedGraph, 5 | visited: Vec, 6 | count: usize, 7 | } 8 | 9 | impl Cc { 10 | pub fn count(&mut self) -> usize { 11 | for v in 0..self.g.v() { 12 | if !self.visited[v] { 13 | self.dfs(v); 14 | self.count += 1; 15 | } 16 | } 17 | self.count 18 | } 19 | 20 | pub fn new(g: WeightedGraph) -> Self { 21 | let v = g.v(); 22 | Self { 23 | g, 24 | visited: vec![false; v], 25 | count: 0, 26 | } 27 | } 28 | 29 | fn dfs(&mut self, v: usize) { 30 | self.visited[v] = true; 31 | for w in self.g.adj_edge(v) { 32 | if !self.visited[w] { 33 | self.dfs(w); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use prim::{Prim, PrimImpl}; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod cc; 5 | mod prim; 6 | mod union_find; 7 | mod weighted_edge; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = WeightedGraph::from_file("g.txt"); 12 | let prim = PrimImpl::new(g); 13 | println!("{:#?}", prim.mst()) 14 | } 15 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/src/prim.rs: -------------------------------------------------------------------------------- 1 | use crate::cc::Cc; 2 | use crate::weighted_edge::WeightedEdge; 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub trait Prim { 6 | fn mst(&self) -> Vec; 7 | } 8 | 9 | pub struct PrimImpl { 10 | g: WeightedGraph, 11 | } 12 | 13 | impl PrimImpl { 14 | pub fn new(g: WeightedGraph) -> Self { 15 | Self { g } 16 | } 17 | } 18 | 19 | impl Prim for PrimImpl { 20 | fn mst(&self) -> Vec { 21 | let mut cc = Cc::new(self.g.clone()); 22 | if cc.count() > 1 { 23 | return vec![]; 24 | } 25 | 26 | let mut mst = Vec::with_capacity(self.g.v() + 1); 27 | let mut visited = vec![false; self.g.v()]; 28 | visited[0] = true; 29 | for _i in 1..self.g.v() { 30 | let mut min_edge = WeightedEdge::new(self.g.v(), self.g.v(), i32::MAX); 31 | for v in 0..self.g.v() { 32 | if visited[v] { 33 | for w in self.g.adj_edge(v) { 34 | if !visited[w] && self.g.get_weight(v, w).unwrap() < min_edge.weight() { 35 | min_edge = WeightedEdge::new(v, w, self.g.get_weight(v, w).unwrap()); 36 | } 37 | } 38 | } 39 | } 40 | visited[min_edge.v()] = true; 41 | visited[min_edge.w()] = true; 42 | mst.push(min_edge); 43 | } 44 | 45 | mst 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/src/union_find.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub struct UnionFind { 4 | parent: Vec, 5 | } 6 | 7 | impl UnionFind { 8 | pub fn new(n: usize) -> Self { 9 | let mut parent = Vec::with_capacity(n); 10 | for i in 0..n { 11 | parent.push(i); 12 | } 13 | 14 | Self { parent } 15 | } 16 | 17 | pub fn find(&mut self, p: usize) -> usize { 18 | if self.parent[p] != p { 19 | self.parent[p] = self.find(self.parent[p]); 20 | } 21 | self.parent[p] 22 | } 23 | 24 | pub fn is_connected(&mut self, p: usize, q: usize) -> bool { 25 | self.find(p) == self.find(q) 26 | } 27 | 28 | pub fn union(&mut self, p: usize, q: usize) { 29 | let l = self.find(p); 30 | let r = self.find(q); 31 | 32 | if l == r { 33 | return; 34 | } 35 | self.parent[l] = r; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/08-Prim-Algorithm/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | pub struct WeightedEdge { 6 | v: usize, 7 | w: usize, 8 | weight: i32, 9 | } 10 | 11 | impl WeightedEdge { 12 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 13 | Self { v, w, weight } 14 | } 15 | 16 | pub fn weight(&self) -> i32 { 17 | self.weight 18 | } 19 | 20 | pub fn w(&self) -> usize { 21 | self.w 22 | } 23 | 24 | pub fn v(&self) -> usize { 25 | self.v 26 | } 27 | } 28 | 29 | impl Debug for WeightedEdge { 30 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 31 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter11-09" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter11-09" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/g.txt: -------------------------------------------------------------------------------- 1 | 7 12 2 | 0 1 2 3 | 0 3 7 4 | 0 5 2 5 | 1 2 1 6 | 1 3 4 7 | 1 4 3 8 | 1 5 5 9 | 2 4 4 10 | 2 5 4 11 | 3 4 1 12 | 3 6 5 13 | 4 6 7 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/src/cc.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Cc { 4 | g: WeightedGraph, 5 | visited: Vec, 6 | count: usize, 7 | } 8 | 9 | impl Cc { 10 | pub fn count(&mut self) -> usize { 11 | for v in 0..self.g.v() { 12 | if !self.visited[v] { 13 | self.dfs(v); 14 | self.count += 1; 15 | } 16 | } 17 | self.count 18 | } 19 | 20 | pub fn new(g: WeightedGraph) -> Self { 21 | let v = g.v(); 22 | Self { 23 | g, 24 | visited: vec![false; v], 25 | count: 0, 26 | } 27 | } 28 | 29 | fn dfs(&mut self, v: usize) { 30 | self.visited[v] = true; 31 | for w in self.g.adj_edge(v) { 32 | if !self.visited[w] { 33 | self.dfs(w); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/src/main.rs: -------------------------------------------------------------------------------- 1 | use prim::{Prim, PrimImpl}; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod cc; 5 | mod prim; 6 | mod weighted_edge; 7 | mod weighted_graph; 8 | 9 | fn main() { 10 | let g = WeightedGraph::from_file("g.txt"); 11 | let prim = PrimImpl::new(g); 12 | println!("{:#?}", prim.mst()) 13 | } 14 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/src/prim.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BinaryHeap; 2 | 3 | use crate::cc::Cc; 4 | use crate::weighted_edge::WeightedEdge; 5 | use crate::weighted_graph::WeightedGraph; 6 | 7 | pub trait Prim { 8 | fn mst(&self) -> Vec; 9 | } 10 | 11 | pub struct PrimImpl { 12 | g: WeightedGraph, 13 | } 14 | 15 | impl PrimImpl { 16 | pub fn new(g: WeightedGraph) -> Self { 17 | Self { g } 18 | } 19 | } 20 | 21 | impl Prim for PrimImpl { 22 | fn mst(&self) -> Vec { 23 | let mut cc = Cc::new(self.g.clone()); 24 | if cc.count() > 1 { 25 | return vec![]; 26 | } 27 | 28 | let mut mst = Vec::with_capacity(self.g.v() + 1); 29 | let mut visited = vec![false; self.g.v()]; 30 | visited[0] = true; 31 | 32 | let mut heap = BinaryHeap::new(); 33 | for w in self.g.adj_edge(0) { 34 | heap.push(WeightedEdge::new(0, w, self.g.get_weight(0, w).unwrap())); 35 | } 36 | 37 | while let Some(edge) = heap.pop() { 38 | if visited[edge.v()] && visited[edge.w()] { 39 | continue; 40 | } 41 | 42 | let newv = { 43 | if visited[edge.v()] { 44 | edge.w() 45 | } else { 46 | edge.v() 47 | } 48 | }; 49 | visited[newv] = true; 50 | for w in self.g.adj_edge(newv) { 51 | if !visited[w] { 52 | heap.push(WeightedEdge::new( 53 | newv, 54 | w, 55 | self.g.get_weight(newv, w).unwrap(), 56 | )); 57 | } 58 | } 59 | 60 | // move edge into mst, so we need to do it in the end of loop 61 | mst.push(edge); 62 | } 63 | mst 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /11-Minimum-Tree-Spanning/09-Prim-Algorithm-Optimized/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | #[derive(Eq)] 6 | pub struct WeightedEdge { 7 | v: usize, 8 | w: usize, 9 | weight: i32, 10 | } 11 | 12 | impl WeightedEdge { 13 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 14 | Self { v, w, weight } 15 | } 16 | 17 | pub fn weight(&self) -> i32 { 18 | self.weight 19 | } 20 | 21 | pub fn w(&self) -> usize { 22 | self.w 23 | } 24 | 25 | pub fn v(&self) -> usize { 26 | self.v 27 | } 28 | } 29 | 30 | impl Debug for WeightedEdge { 31 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 32 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 33 | } 34 | } 35 | 36 | impl Ord for WeightedEdge { 37 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 38 | other.weight.cmp(&self.weight) 39 | } 40 | } 41 | 42 | impl PartialOrd for WeightedEdge { 43 | fn partial_cmp(&self, other: &Self) -> Option { 44 | Some(other.weight.cmp(&self.weight)) 45 | } 46 | } 47 | 48 | impl PartialEq for WeightedEdge { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.weight == other.weight 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter12-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter12-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/src/dijkstra.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Dijkstra { 4 | g: WeightedGraph, 5 | s: usize, 6 | visited: Vec, 7 | dis: Vec, 8 | } 9 | 10 | impl Dijkstra { 11 | pub fn new(g: WeightedGraph, s: usize) -> Self { 12 | let mut visited = vec![false; g.v()]; 13 | let mut dis = vec![i32::MAX; g.v()]; 14 | 15 | // Dijkstra algorithm 16 | dis[0] = 0; 17 | loop { 18 | // find out the minimum point 19 | let mut cur = -1; 20 | let mut min = i32::MAX; 21 | for v in 0..g.v() { 22 | if !visited[v] && dis[v] < min { 23 | cur = v as i32; 24 | min = dis[v]; 25 | } 26 | } 27 | 28 | if cur == -1 { 29 | break; 30 | } 31 | 32 | // update others 33 | let cur = cur as usize; 34 | visited[cur] = true; 35 | for w in g.adj_edge(cur) { 36 | if !visited[w] && dis[w] > dis[cur] + g.get_weight(cur, w).unwrap() { 37 | dis[w] = dis[cur] + g.get_weight(cur, w).unwrap(); 38 | } 39 | } 40 | } 41 | 42 | Self { g, s, visited, dis } 43 | } 44 | 45 | pub fn is_connected_to(&self, w: usize) -> bool { 46 | self.g.validate_vertex(w); 47 | self.visited[w] 48 | } 49 | 50 | pub fn dis_to(&self, w: usize) -> i32 { 51 | self.g.validate_vertex(w); 52 | self.dis[w] 53 | } 54 | 55 | pub fn s(&self) -> usize { 56 | self.s 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use dijkstra::Dijkstra; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod dijkstra; 5 | mod weighted_edge; 6 | mod weighted_graph; 7 | 8 | fn main() { 9 | let g = WeightedGraph::from_file("g.txt"); 10 | let v = g.v(); 11 | let dij = Dijkstra::new(g, 0); 12 | for v in 0..v { 13 | print!("{} ", dij.dis_to(v)); 14 | } 15 | println!(); 16 | } 17 | -------------------------------------------------------------------------------- /12-Shortest-Path/03-Dijkstra-Algorithm/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | #[derive(Eq)] 6 | pub struct WeightedEdge { 7 | v: usize, 8 | w: usize, 9 | weight: i32, 10 | } 11 | 12 | impl WeightedEdge { 13 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 14 | Self { v, w, weight } 15 | } 16 | 17 | pub fn weight(&self) -> i32 { 18 | self.weight 19 | } 20 | 21 | pub fn w(&self) -> usize { 22 | self.w 23 | } 24 | 25 | pub fn v(&self) -> usize { 26 | self.v 27 | } 28 | } 29 | 30 | impl Debug for WeightedEdge { 31 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 32 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 33 | } 34 | } 35 | 36 | impl Ord for WeightedEdge { 37 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 38 | other.weight.cmp(&self.weight) 39 | } 40 | } 41 | 42 | impl PartialOrd for WeightedEdge { 43 | fn partial_cmp(&self, other: &Self) -> Option { 44 | Some(other.weight.cmp(&self.weight)) 45 | } 46 | } 47 | 48 | impl PartialEq for WeightedEdge { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.weight == other.weight 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter12-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter12-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/g.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/src/dijkstra.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::collections::BinaryHeap; 4 | 5 | use crate::weighted_graph::WeightedGraph; 6 | 7 | pub struct Dijkstra { 8 | g: WeightedGraph, 9 | s: usize, 10 | visited: Vec, 11 | dis: Vec, 12 | } 13 | 14 | #[derive(PartialEq, Eq)] 15 | struct Node { 16 | v: usize, 17 | dis: i32, 18 | } 19 | 20 | impl Ord for Node { 21 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 22 | other.dis.cmp(&self.dis).then_with(|| self.v.cmp(&other.v)) 23 | } 24 | } 25 | 26 | impl PartialOrd for Node { 27 | fn partial_cmp(&self, other: &Self) -> Option { 28 | Some(self.cmp(other)) 29 | } 30 | } 31 | 32 | impl Dijkstra { 33 | pub fn new(g: WeightedGraph, s: usize) -> Self { 34 | let mut visited = vec![false; g.v()]; 35 | let mut dis = vec![i32::MAX; g.v()]; 36 | 37 | // Dijkstra algorithm 38 | dis[s] = 0; 39 | let mut heap = BinaryHeap::new(); 40 | heap.push(Node { v: s, dis: 0 }); 41 | while let Some(Node { v, dis: d }) = heap.pop() { 42 | if visited[v] { 43 | continue; 44 | } 45 | // update others 46 | visited[v] = true; 47 | for w in g.adj_edge(v) { 48 | if !visited[w] && dis[w] > d + g.get_weight(v, w).unwrap() { 49 | dis[w] = d + g.get_weight(v, w).unwrap(); 50 | heap.push(Node { v: w, dis: dis[w] }) 51 | } 52 | } 53 | } 54 | 55 | Self { g, s, visited, dis } 56 | } 57 | 58 | pub fn is_connected_to(&self, w: usize) -> bool { 59 | self.g.validate_vertex(w); 60 | self.visited[w] 61 | } 62 | 63 | pub fn dis_to(&self, w: usize) -> i32 { 64 | self.g.validate_vertex(w); 65 | self.dis[w] 66 | } 67 | 68 | pub fn s(&self) -> usize { 69 | self.s 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/src/main.rs: -------------------------------------------------------------------------------- 1 | use dijkstra::Dijkstra; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod dijkstra; 5 | mod weighted_edge; 6 | mod weighted_graph; 7 | 8 | fn main() { 9 | let g = WeightedGraph::from_file("g.txt"); 10 | let v = g.v(); 11 | let dij = Dijkstra::new(g, 0); 12 | for v in 0..v { 13 | print!("{} ", dij.dis_to(v)); 14 | } 15 | println!(); 16 | } 17 | -------------------------------------------------------------------------------- /12-Shortest-Path/04-Dijkstra-Algorithm-Optimized/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | #[derive(Eq)] 6 | pub struct WeightedEdge { 7 | v: usize, 8 | w: usize, 9 | weight: i32, 10 | } 11 | 12 | impl WeightedEdge { 13 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 14 | Self { v, w, weight } 15 | } 16 | 17 | pub fn weight(&self) -> i32 { 18 | self.weight 19 | } 20 | 21 | pub fn w(&self) -> usize { 22 | self.w 23 | } 24 | 25 | pub fn v(&self) -> usize { 26 | self.v 27 | } 28 | } 29 | 30 | impl Debug for WeightedEdge { 31 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 32 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 33 | } 34 | } 35 | 36 | impl Ord for WeightedEdge { 37 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 38 | other.weight.cmp(&self.weight) 39 | } 40 | } 41 | 42 | impl PartialOrd for WeightedEdge { 43 | fn partial_cmp(&self, other: &Self) -> Option { 44 | Some(other.weight.cmp(&self.weight)) 45 | } 46 | } 47 | 48 | impl PartialEq for WeightedEdge { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.weight == other.weight 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter12-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter12-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/g2.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 -1 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/src/bellman_ford.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct BellmanFord { 6 | g: WeightedGraph, 7 | dis: Vec, 8 | s: usize, 9 | has_negative_cycle: bool, 10 | } 11 | 12 | impl BellmanFord { 13 | pub fn new(g: WeightedGraph, s: usize) -> Self { 14 | let mut dis = vec![i32::MAX; g.v()]; 15 | let mut has_negative_cycle = false; 16 | dis[s] = 0; 17 | 18 | for _pass in 1..g.v() { 19 | for v in 0..g.v() { 20 | for w in g.adj_edge(v) { 21 | if dis[v] < i32::MAX && dis[v] + g.get_weight(v, w).unwrap() < dis[w] { 22 | dis[w] = dis[v] + g.get_weight(v, w).unwrap(); 23 | } 24 | } 25 | } 26 | } 27 | 28 | // detect negative cycle 29 | for v in 0..g.v() { 30 | for w in g.adj_edge(v) { 31 | if dis[v] < i32::MAX && dis[v] + g.get_weight(v, w).unwrap() < dis[w] { 32 | has_negative_cycle = true; 33 | } 34 | } 35 | } 36 | 37 | Self { 38 | g, 39 | dis, 40 | s, 41 | has_negative_cycle, 42 | } 43 | } 44 | 45 | pub fn has_negative_cycle(&self) -> bool { 46 | self.has_negative_cycle 47 | } 48 | 49 | pub fn is_connected_to(&self, w: usize) -> bool { 50 | self.g.validate_vertex(w); 51 | self.dis[w] != i32::MAX 52 | } 53 | 54 | pub fn dis_to(&self, w: usize) -> Option { 55 | self.g.validate_vertex(w); 56 | if self.has_negative_cycle { 57 | // println!("Negative cycle detected"); 58 | None 59 | } else { 60 | Some(self.dis[w]) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/src/dijkstra.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::collections::BinaryHeap; 4 | 5 | use crate::weighted_graph::WeightedGraph; 6 | 7 | pub struct Dijkstra { 8 | g: WeightedGraph, 9 | s: usize, 10 | visited: Vec, 11 | dis: Vec, 12 | } 13 | 14 | #[derive(PartialEq, Eq)] 15 | struct Node { 16 | v: usize, 17 | dis: i32, 18 | } 19 | 20 | impl Ord for Node { 21 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 22 | other.dis.cmp(&self.dis).then_with(|| self.v.cmp(&other.v)) 23 | } 24 | } 25 | 26 | impl PartialOrd for Node { 27 | fn partial_cmp(&self, other: &Self) -> Option { 28 | Some(self.cmp(other)) 29 | } 30 | } 31 | 32 | impl Dijkstra { 33 | pub fn new(g: WeightedGraph, s: usize) -> Self { 34 | let mut visited = vec![false; g.v()]; 35 | let mut dis = vec![i32::MAX; g.v()]; 36 | 37 | // Dijkstra algorithm 38 | dis[s] = 0; 39 | let mut heap = BinaryHeap::new(); 40 | heap.push(Node { v: s, dis: 0 }); 41 | while let Some(Node { v, dis: d }) = heap.pop() { 42 | if visited[v] { 43 | continue; 44 | } 45 | // update others 46 | visited[v] = true; 47 | for w in g.adj_edge(v) { 48 | if !visited[w] && dis[w] > d + g.get_weight(v, w).unwrap() { 49 | dis[w] = d + g.get_weight(v, w).unwrap(); 50 | heap.push(Node { v: w, dis: dis[w] }) 51 | } 52 | } 53 | } 54 | 55 | Self { g, s, visited, dis } 56 | } 57 | 58 | pub fn is_connected_to(&self, w: usize) -> bool { 59 | self.g.validate_vertex(w); 60 | self.visited[w] 61 | } 62 | 63 | pub fn dis_to(&self, w: usize) -> i32 { 64 | self.g.validate_vertex(w); 65 | self.dis[w] 66 | } 67 | 68 | pub fn s(&self) -> usize { 69 | self.s 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use bellman_ford::BellmanFord; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod bellman_ford; 5 | mod dijkstra; 6 | mod weighted_edge; 7 | mod weighted_graph; 8 | 9 | fn main() { 10 | let g = WeightedGraph::from_file("g.txt"); 11 | let v = g.v(); 12 | let bf = BellmanFord::new(g, 0); 13 | 14 | // use ∞ present we have a negative cycle 15 | for v in 0..v { 16 | print!( 17 | "{} ", 18 | if let Some(dis) = bf.dis_to(v) { 19 | dis.to_string() 20 | } else { 21 | "∞".to_string() 22 | } 23 | ); 24 | } 25 | println!(); 26 | } 27 | -------------------------------------------------------------------------------- /12-Shortest-Path/08-Bellman-Ford-Algorithm/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | #[derive(Eq)] 6 | pub struct WeightedEdge { 7 | v: usize, 8 | w: usize, 9 | weight: i32, 10 | } 11 | 12 | impl WeightedEdge { 13 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 14 | Self { v, w, weight } 15 | } 16 | 17 | pub fn weight(&self) -> i32 { 18 | self.weight 19 | } 20 | 21 | pub fn w(&self) -> usize { 22 | self.w 23 | } 24 | 25 | pub fn v(&self) -> usize { 26 | self.v 27 | } 28 | } 29 | 30 | impl Debug for WeightedEdge { 31 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 32 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 33 | } 34 | } 35 | 36 | impl Ord for WeightedEdge { 37 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 38 | other.weight.cmp(&self.weight) 39 | } 40 | } 41 | 42 | impl PartialOrd for WeightedEdge { 43 | fn partial_cmp(&self, other: &Self) -> Option { 44 | Some(other.weight.cmp(&self.weight)) 45 | } 46 | } 47 | 48 | impl PartialEq for WeightedEdge { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.weight == other.weight 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter12-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter12-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/g.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/g2.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 -1 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/src/bellman_ford.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct BellmanFord { 6 | g: WeightedGraph, 7 | dis: Vec, 8 | s: usize, 9 | has_negative_cycle: bool, 10 | } 11 | 12 | impl BellmanFord { 13 | pub fn new(g: WeightedGraph, s: usize) -> Self { 14 | let mut dis = vec![i32::MAX; g.v()]; 15 | let mut has_negative_cycle = false; 16 | dis[s] = 0; 17 | 18 | for _pass in 1..g.v() { 19 | for v in 0..g.v() { 20 | for w in g.adj_edge(v) { 21 | if dis[v] < i32::MAX && dis[v] + g.get_weight(v, w).unwrap() < dis[w] { 22 | dis[w] = dis[v] + g.get_weight(v, w).unwrap(); 23 | } 24 | } 25 | } 26 | } 27 | 28 | // detect negative cycle 29 | for v in 0..g.v() { 30 | for w in g.adj_edge(v) { 31 | if dis[v] < i32::MAX && dis[v] + g.get_weight(v, w).unwrap() < dis[w] { 32 | has_negative_cycle = true; 33 | } 34 | } 35 | } 36 | 37 | Self { 38 | g, 39 | dis, 40 | s, 41 | has_negative_cycle, 42 | } 43 | } 44 | 45 | pub fn has_negative_cycle(&self) -> bool { 46 | self.has_negative_cycle 47 | } 48 | 49 | pub fn is_connected_to(&self, w: usize) -> bool { 50 | self.g.validate_vertex(w); 51 | self.dis[w] != i32::MAX 52 | } 53 | 54 | pub fn dis_to(&self, w: usize) -> Option { 55 | self.g.validate_vertex(w); 56 | if self.has_negative_cycle { 57 | // println!("Negative cycle detected"); 58 | None 59 | } else { 60 | Some(self.dis[w]) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/src/dijkstra.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::collections::BinaryHeap; 4 | 5 | use crate::weighted_graph::WeightedGraph; 6 | 7 | pub struct Dijkstra { 8 | g: WeightedGraph, 9 | s: usize, 10 | visited: Vec, 11 | dis: Vec, 12 | } 13 | 14 | #[derive(PartialEq, Eq)] 15 | struct Node { 16 | v: usize, 17 | dis: i32, 18 | } 19 | 20 | impl Ord for Node { 21 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 22 | other.dis.cmp(&self.dis).then_with(|| self.v.cmp(&other.v)) 23 | } 24 | } 25 | 26 | impl PartialOrd for Node { 27 | fn partial_cmp(&self, other: &Self) -> Option { 28 | Some(self.cmp(other)) 29 | } 30 | } 31 | 32 | impl Dijkstra { 33 | pub fn new(g: WeightedGraph, s: usize) -> Self { 34 | let mut visited = vec![false; g.v()]; 35 | let mut dis = vec![i32::MAX; g.v()]; 36 | 37 | // Dijkstra algorithm 38 | dis[s] = 0; 39 | let mut heap = BinaryHeap::new(); 40 | heap.push(Node { v: s, dis: 0 }); 41 | while let Some(Node { v, dis: d }) = heap.pop() { 42 | if visited[v] { 43 | continue; 44 | } 45 | // update others 46 | visited[v] = true; 47 | for w in g.adj_edge(v) { 48 | if !visited[w] && dis[w] > d + g.get_weight(v, w).unwrap() { 49 | dis[w] = d + g.get_weight(v, w).unwrap(); 50 | heap.push(Node { v: w, dis: dis[w] }) 51 | } 52 | } 53 | } 54 | 55 | Self { g, s, visited, dis } 56 | } 57 | 58 | pub fn is_connected_to(&self, w: usize) -> bool { 59 | self.g.validate_vertex(w); 60 | self.visited[w] 61 | } 62 | 63 | pub fn dis_to(&self, w: usize) -> i32 { 64 | self.g.validate_vertex(w); 65 | self.dis[w] 66 | } 67 | 68 | pub fn s(&self) -> usize { 69 | self.s 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/src/floyed.rs: -------------------------------------------------------------------------------- 1 | use crate::weighted_graph::WeightedGraph; 2 | 3 | pub struct Floyed { 4 | g: WeightedGraph, 5 | dis: Vec>, 6 | has_nagative_cycle: bool, 7 | } 8 | 9 | impl Floyed { 10 | pub fn new(g: WeightedGraph) -> Self { 11 | let mut dis = vec![vec![i32::MAX; g.v()]; g.v()]; 12 | let mut has_nagative_cycle = false; 13 | 14 | for v in 0..g.v() { 15 | dis[v][v] = 0; 16 | for w in g.adj_edge(v) { 17 | dis[v][w] = g.get_weight(v, w).unwrap(); 18 | } 19 | } 20 | 21 | for t in 0..g.v() { 22 | for v in 0..g.v() { 23 | for w in 0..g.v() { 24 | if dis[v][t] < i32::MAX 25 | && dis[t][w] < i32::MAX 26 | && dis[v][t] + dis[t][w] < dis[v][w] 27 | { 28 | dis[v][w] = dis[v][t] + dis[t][w]; 29 | } 30 | } 31 | } 32 | } 33 | 34 | for v in 0..g.v() { 35 | if dis[v][v] < 0 { 36 | has_nagative_cycle = true; 37 | } 38 | } 39 | 40 | Self { 41 | g, 42 | dis, 43 | has_nagative_cycle, 44 | } 45 | } 46 | 47 | pub fn has_nagative_cycle(&self) -> bool { 48 | self.has_nagative_cycle 49 | } 50 | 51 | pub fn is_connected_to(&self, v: usize, w: usize) -> bool { 52 | self.g.validate_vertex(v); 53 | self.g.validate_vertex(w); 54 | self.dis[v][w] == i32::MAX 55 | } 56 | 57 | pub fn dis_to(&self, v: usize, w: usize) -> Option { 58 | self.g.validate_vertex(v); 59 | self.g.validate_vertex(w); 60 | 61 | if self.has_nagative_cycle { 62 | None 63 | } else { 64 | Some(self.dis[v][w]) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/src/main.rs: -------------------------------------------------------------------------------- 1 | use weighted_graph::WeightedGraph; 2 | 3 | use crate::floyed::Floyed; 4 | 5 | mod bellman_ford; 6 | mod dijkstra; 7 | mod floyed; 8 | mod weighted_edge; 9 | mod weighted_graph; 10 | 11 | fn main() { 12 | let g = WeightedGraph::from_file("g.txt"); 13 | let size = g.v(); 14 | let fy = Floyed::new(g); 15 | 16 | // use ∞ present we have a negative cycle 17 | for v in 0..size { 18 | for w in 0..size { 19 | print!( 20 | "{} ", 21 | if let Some(dis) = fy.dis_to(v, w) { 22 | dis.to_string() 23 | } else { 24 | "∞".to_string() 25 | } 26 | ); 27 | } 28 | println!(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /12-Shortest-Path/11-Floyed-Algorithm/src/weighted_edge.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt::Debug; 4 | 5 | #[derive(Eq)] 6 | pub struct WeightedEdge { 7 | v: usize, 8 | w: usize, 9 | weight: i32, 10 | } 11 | 12 | impl WeightedEdge { 13 | pub fn new(v: usize, w: usize, weight: i32) -> Self { 14 | Self { v, w, weight } 15 | } 16 | 17 | pub fn weight(&self) -> i32 { 18 | self.weight 19 | } 20 | 21 | pub fn w(&self) -> usize { 22 | self.w 23 | } 24 | 25 | pub fn v(&self) -> usize { 26 | self.v 27 | } 28 | } 29 | 30 | impl Debug for WeightedEdge { 31 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 32 | f.write_str(format!("({}-{}: {})", self.v, self.w, self.weight).as_str()) 33 | } 34 | } 35 | 36 | impl Ord for WeightedEdge { 37 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 38 | other.weight.cmp(&self.weight) 39 | } 40 | } 41 | 42 | impl PartialOrd for WeightedEdge { 43 | fn partial_cmp(&self, other: &Self) -> Option { 44 | Some(other.weight.cmp(&self.weight)) 45 | } 46 | } 47 | 48 | impl PartialEq for WeightedEdge { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.weight == other.weight 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /13-Directed-Graph/01-Directed-Graph/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-01" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/01-Directed-Graph/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-01" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/01-Directed-Graph/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | mod graph; 6 | mod weighted_graph; 7 | 8 | fn main() { 9 | let g = Graph::from_file("ug.txt", false); 10 | println!("{g}"); 11 | 12 | let g = Graph::from_file("ug.txt", true); 13 | println!("{g}"); 14 | 15 | let g = WeightedGraph::from_file("wg.txt", false); 16 | println!("{g}"); 17 | 18 | let g = WeightedGraph::from_file("wg.txt", true); 19 | println!("{g}"); 20 | } 21 | -------------------------------------------------------------------------------- /13-Directed-Graph/01-Directed-Graph/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | -------------------------------------------------------------------------------- /13-Directed-Graph/01-Directed-Graph/wg.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/src/directed_cycle_detection.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub struct DirectedCycleDetection { 4 | g: Graph, 5 | visited: Vec, 6 | path: Vec, 7 | has_cycle: bool, 8 | } 9 | 10 | impl DirectedCycleDetection { 11 | pub fn new(g: Graph) -> Self { 12 | let visited = vec![false; g.v()]; 13 | let path = vec![false; g.v()]; 14 | let has_cycle = false; 15 | let mut dcd = Self { 16 | g, 17 | visited, 18 | path, 19 | has_cycle, 20 | }; 21 | 22 | for v in 0..dcd.g.v() { 23 | if !dcd.visited[v] && dcd.dfs(v) { 24 | break; 25 | } 26 | } 27 | 28 | dcd 29 | } 30 | 31 | fn dfs(&mut self, v: usize) -> bool { 32 | self.visited[v] = true; 33 | self.path[v] = true; 34 | 35 | for w in self.g.adj_edge(v) { 36 | if !self.visited[w] { 37 | if self.dfs(w) { 38 | return true; 39 | } 40 | } else if self.path[w] { 41 | self.has_cycle = true; 42 | return true; 43 | } 44 | } 45 | self.path[v] = false; 46 | false 47 | } 48 | 49 | pub fn has_cycle(&self) -> bool { 50 | self.has_cycle 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | 3 | use crate::directed_cycle_detection::DirectedCycleDetection; 4 | 5 | mod directed_cycle_detection; 6 | mod graph; 7 | 8 | fn main() { 9 | let g = Graph::from_file("ug.txt", true); 10 | let dcd = DirectedCycleDetection::new(g); 11 | println!("{}", dcd.has_cycle()); 12 | 13 | let g = Graph::from_file("ug2.txt", true); 14 | let dcd = DirectedCycleDetection::new(g); 15 | println!("{}", dcd.has_cycle()); 16 | } 17 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/ug2.txt: -------------------------------------------------------------------------------- 1 | 5 6 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | 3 0 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/03-Directed-Cycle-Detection/wg.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-04" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | 3 | use crate::directed_cycle_detection::DirectedCycleDetection; 4 | 5 | mod directed_cycle_detection; 6 | mod graph; 7 | 8 | fn main() { 9 | let g = Graph::from_file("ug.txt", true); 10 | let dcd = DirectedCycleDetection::new(g); 11 | println!("{}", dcd.has_cycle()); 12 | 13 | let g = Graph::from_file("ug2.txt", true); 14 | let dcd = DirectedCycleDetection::new(g); 15 | println!("{}", dcd.has_cycle()); 16 | } 17 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/ug2.txt: -------------------------------------------------------------------------------- 1 | 5 6 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | 3 0 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/04-Directed-Graph-Degrees/wg.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 4 3 | 0 2 2 4 | 1 2 1 5 | 1 3 2 6 | 1 4 3 7 | 2 3 4 8 | 2 4 5 9 | 3 4 1 10 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-05" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-05" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/src/euler_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub trait EulerLoop { 4 | fn has_loop(&self) -> bool; 5 | fn euler_loop(&self) -> Vec; 6 | } 7 | 8 | pub struct EulerLoopImpl { 9 | g: Graph, 10 | } 11 | 12 | impl EulerLoopImpl { 13 | pub fn new(g: Graph) -> Self { 14 | if !g.directed() { 15 | panic!("Don't support undirected graph"); 16 | } 17 | Self { g } 18 | } 19 | } 20 | 21 | impl EulerLoop for EulerLoopImpl { 22 | fn has_loop(&self) -> bool { 23 | // check CC 24 | // let mut visited = vec![false; self.g.v()]; 25 | // self.dfs(&mut visited, 0); 26 | // for v in visited { 27 | // if !v { 28 | // return false; // not CC 29 | // } 30 | // } 31 | 32 | for v in 0..self.g.v() { 33 | if self.g.in_degree(v) != self.g.out_degree(v) { 34 | return false; // odd degree 35 | } 36 | } 37 | 38 | true 39 | } 40 | 41 | fn euler_loop(&self) -> Vec { 42 | if !self.has_loop() { 43 | return vec![]; 44 | } 45 | 46 | let mut res = Vec::with_capacity(self.g.e() + 1); 47 | let mut g = self.g.clone(); 48 | let mut stack = vec![]; 49 | let mut curv = 0; 50 | // important, push curv first but this curv will not push into res 51 | stack.push(curv); 52 | while !stack.is_empty() { 53 | if g.out_degree(curv) != 0 { 54 | stack.push(curv); 55 | let w = g.adj_edge(curv).next().unwrap(); 56 | g.remove_edge(curv, w); 57 | curv = w; 58 | } else { 59 | res.push(curv); 60 | curv = stack.pop().unwrap(); 61 | } 62 | } 63 | 64 | res.reverse(); 65 | res 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/src/main.rs: -------------------------------------------------------------------------------- 1 | use euler_loop::{EulerLoop, EulerLoopImpl}; 2 | use graph::Graph; 3 | 4 | mod euler_loop; 5 | mod graph; 6 | 7 | fn main() { 8 | let g = Graph::from_file("ug.txt", true); 9 | let el = EulerLoopImpl::new(g); 10 | println!("{:?}", el.euler_loop()); 11 | 12 | let g = Graph::from_file("ug2.txt", true); 13 | let el = EulerLoopImpl::new(g); 14 | println!("{:?}", el.euler_loop()); 15 | } 16 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | -------------------------------------------------------------------------------- /13-Directed-Graph/05-Directed-Euler-Loop/ug2.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 0 6 | 2 4 7 | 3 1 8 | 3 2 9 | 4 3 10 | -------------------------------------------------------------------------------- /13-Directed-Graph/07-Topological-Sort/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-07" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/07-Topological-Sort/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-07" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/07-Topological-Sort/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use topo_sort::TopoSort; 3 | 4 | mod graph; 5 | mod topo_sort; 6 | 7 | fn main() { 8 | let g = Graph::from_file("ug.txt", true); 9 | let ts = TopoSort::new(g); 10 | println!("{:?}", ts.result()); 11 | } 12 | -------------------------------------------------------------------------------- /13-Directed-Graph/07-Topological-Sort/src/topo_sort.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::graph::Graph; 4 | use std::collections::VecDeque; 5 | 6 | pub struct TopoSort { 7 | g: Graph, 8 | res: Vec, 9 | indegree: Vec, 10 | has_cycle: bool, 11 | } 12 | 13 | impl TopoSort { 14 | pub fn new(g: Graph) -> Self { 15 | let mut res = Vec::with_capacity(g.v()); 16 | let mut indegree = Vec::with_capacity(g.v()); 17 | let mut has_cycle = false; 18 | 19 | for v in 0..g.v() { 20 | indegree.push(g.in_degree(v)); 21 | } 22 | 23 | let mut q = VecDeque::new(); 24 | indegree 25 | .iter() 26 | .enumerate() 27 | .filter(|(_, &v)| v == 0) 28 | .for_each(|(i, _)| q.push_back(i)); 29 | 30 | while let Some(v) = q.pop_front() { 31 | res.push(v); 32 | for w in g.adj_edge(v) { 33 | indegree[w] -= 1; 34 | if indegree[w] == 0 { 35 | q.push_back(w); 36 | } 37 | } 38 | } 39 | 40 | if res.len() < g.v() { 41 | res.clear(); 42 | has_cycle = true; 43 | } 44 | 45 | Self { 46 | g, 47 | res, 48 | indegree, 49 | has_cycle, 50 | } 51 | } 52 | 53 | pub fn has_cycle(&self) -> bool { 54 | self.has_cycle 55 | } 56 | 57 | pub fn result(&self) -> Vec { 58 | self.res.clone() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /13-Directed-Graph/07-Topological-Sort/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 1 3 5 | 2 4 6 | 3 2 7 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter13-12" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter13-12" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/src/dfs.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | pub struct Dfs { 4 | g: Graph, 5 | visited: Vec, 6 | post: Vec, 7 | } 8 | 9 | impl Dfs { 10 | pub fn new(g: Graph) -> Self { 11 | let visited = vec![false; g.v()]; 12 | let post = Vec::with_capacity(g.v()); 13 | 14 | let mut this = Self { g, visited, post }; 15 | 16 | for v in 0..this.g.v() { 17 | if !this.visited[v] { 18 | this.dfs(v); 19 | } 20 | } 21 | 22 | this 23 | } 24 | 25 | fn dfs(&mut self, v: usize) { 26 | self.visited[v] = true; 27 | for w in self.g.adj_edge(v) { 28 | if !self.visited[w] { 29 | self.dfs(w); 30 | } 31 | } 32 | self.post.push(v); 33 | } 34 | 35 | pub fn post(&self) -> Vec { 36 | self.post.clone() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/src/main.rs: -------------------------------------------------------------------------------- 1 | use graph::Graph; 2 | use scc::Scc; 3 | 4 | mod dfs; 5 | mod graph; 6 | mod scc; 7 | 8 | fn main() { 9 | let g = Graph::from_file("ug.txt", true); 10 | let scc = Scc::new(g); 11 | 12 | println!("{:?}", scc.component()); 13 | } 14 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/src/scc.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::{dfs::Dfs, graph::Graph}; 4 | 5 | #[derive(Debug)] 6 | pub struct Scc { 7 | g: Graph, 8 | visited: Vec, 9 | cnt: usize, 10 | } 11 | 12 | impl Scc { 13 | pub fn new(mut g: Graph) -> Self { 14 | let visited = vec![-1; g.v()]; 15 | let cnt = 0; 16 | 17 | let mut order = Dfs::new(g.new_reverse()).post(); 18 | order.reverse(); 19 | 20 | let mut this = Self { g, visited, cnt }; 21 | 22 | for v in order { 23 | if this.visited[v] == -1 { 24 | this.dfs(v, this.cnt as i32); 25 | this.cnt += 1; 26 | } 27 | } 28 | 29 | this 30 | } 31 | 32 | fn dfs(&mut self, v: usize, cnt: i32) { 33 | self.visited[v] = cnt; 34 | for w in self.g.adj_edge(v) { 35 | if self.visited[w] == -1 { 36 | self.dfs(w, cnt); 37 | } 38 | } 39 | } 40 | 41 | pub fn strong_connected(&self, v: usize, w: usize) -> bool { 42 | self.visited[v] == self.visited[w] 43 | } 44 | 45 | pub fn component(&self) -> Vec> { 46 | let mut res = vec![vec![]; self.cnt]; 47 | for v in 0..self.g.v() { 48 | res[self.visited[v] as usize].push(v); 49 | } 50 | res 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /13-Directed-Graph/12-SCC/ug.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 3 | 1 2 4 | 2 3 5 | 3 1 6 | 2 4 7 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter14-06" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter14-06" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/network.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 0 1 3 3 | 0 2 2 4 | 1 2 5 5 | 1 3 2 6 | 2 3 3 7 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/network2.txt: -------------------------------------------------------------------------------- 1 | 6 9 2 | 0 1 9 3 | 0 3 9 4 | 1 2 8 5 | 1 3 10 6 | 2 5 10 7 | 3 2 1 8 | 3 4 3 9 | 4 2 8 10 | 4 5 7 11 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/src/main.rs: -------------------------------------------------------------------------------- 1 | use max_flow::MaxFlow; 2 | use weighted_graph::WeightedGraph; 3 | 4 | mod max_flow; 5 | mod weighted_graph; 6 | 7 | fn main() { 8 | let g = WeightedGraph::from_file("network.txt", true); 9 | let mf = MaxFlow::new(g.clone(), 0, 3); 10 | println!("{}", mf.maxflow()); 11 | for v in 0..g.v() { 12 | for w in g.adj_edge(v) { 13 | println!( 14 | "{}-{}: {} / {}", 15 | v, 16 | w, 17 | mf.get_flow(v, w).unwrap(), 18 | g.get_weight(v, w).unwrap() 19 | ); 20 | } 21 | } 22 | 23 | let g = WeightedGraph::from_file("network2.txt", true); 24 | let mf = MaxFlow::new(g.clone(), 0, 5); 25 | println!("{}", mf.maxflow()); 26 | for v in 0..g.v() { 27 | for w in g.adj_edge(v) { 28 | println!( 29 | "{}-{}: {} / {}", 30 | v, 31 | w, 32 | mf.get_flow(v, w).unwrap(), 33 | g.get_weight(v, w).unwrap() 34 | ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /14-Network-Flows/06-Edmonds-Karp-Algorithm-Completed/src/max_flow.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct MaxFlow { 6 | rg: WeightedGraph, 7 | s: usize, 8 | t: usize, 9 | maxflow: usize, 10 | } 11 | 12 | impl MaxFlow { 13 | pub fn new(g: WeightedGraph, s: usize, t: usize) -> Self { 14 | if !g.directed() { 15 | panic!("Only support directed graph"); 16 | } 17 | if g.v() < 2 { 18 | panic!("Graph should has more than one vertex"); 19 | } 20 | g.validate_vertex(s); 21 | g.validate_vertex(t); 22 | 23 | if s == t { 24 | panic!("start vertex can't be the same as end vertex"); 25 | } 26 | 27 | let rg = WeightedGraph::new_rg(&g); 28 | let mut q = VecDeque::new(); 29 | q.push_back(s); 30 | let maxflow = 0; 31 | let mut this = Self { rg, s, t, maxflow }; 32 | 33 | while let Some(path) = this.get_augementing_path() { 34 | let mut f = i32::MAX; 35 | for i in 1..path.len() { 36 | let v = path[i - 1]; 37 | let w = path[i]; 38 | f = i32::min(f, this.rg.get_weight(v, w).unwrap()); 39 | } 40 | this.maxflow += f as usize; 41 | for i in 1..path.len() { 42 | let v = path[i - 1]; 43 | let w = path[i]; 44 | this.rg 45 | .set_weight(v, w, this.rg.get_weight(v, w).unwrap() - f as i32); 46 | this.rg 47 | .set_weight(w, v, this.rg.get_weight(w, v).unwrap() + f as i32); 48 | } 49 | } 50 | 51 | this 52 | } 53 | 54 | fn get_augementing_path(&mut self) -> Option> { 55 | let mut pre = vec![-1; self.rg.v()]; 56 | let mut q = VecDeque::new(); 57 | q.push_back(self.s); 58 | pre[self.s] = self.s as i32; 59 | while let Some(v) = q.pop_front() { 60 | if v == self.t { 61 | break; 62 | } 63 | for w in self.rg.adj_edge(v) { 64 | if pre[w] == -1 && self.rg.get_weight(v, w).unwrap() > 0 { 65 | q.push_back(w); 66 | pre[w] = v as i32; 67 | } 68 | } 69 | } 70 | 71 | if pre[self.t] == -1 { 72 | return None; 73 | } 74 | 75 | let mut res = vec![]; 76 | let mut cur = self.t; 77 | while cur as usize != self.s { 78 | res.push(cur); 79 | cur = pre[cur] as usize; 80 | } 81 | res.push(self.s); 82 | res.reverse(); 83 | Some(res) 84 | } 85 | 86 | pub fn maxflow(&self) -> usize { 87 | self.maxflow 88 | } 89 | 90 | pub fn get_flow(&self, v: usize, w: usize) -> Option { 91 | if self.rg.has_edge(v, w) { 92 | return Some(self.rg.get_weight(w, v).unwrap()); 93 | } 94 | None 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter15-03" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter15-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/g.txt: -------------------------------------------------------------------------------- 1 | 8 6 2 | 0 4 3 | 0 6 4 | 1 4 5 | 2 6 6 | 3 5 7 | 3 7 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/g2.txt: -------------------------------------------------------------------------------- 1 | 8 7 2 | 0 4 3 | 0 6 4 | 1 4 5 | 1 7 6 | 2 6 7 | 3 5 8 | 3 7 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/src/bipartition.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | /// `colors`: 表示颜色 4 | /// - 0 -> blue 5 | /// - 1 -> green 6 | pub fn is_bipartition(g: &Graph) -> (bool, Option>) { 7 | let mut visited = vec![false; g.v()]; 8 | let mut colors = vec![-1; g.v()]; 9 | for v in 0..g.v() { 10 | if !visited[v] && !__dfs(g, v, &mut visited, &mut colors, 0) { 11 | return (false, None); 12 | } 13 | } 14 | 15 | (true, Some(colors)) 16 | } 17 | 18 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, colors: &mut Vec, color: i32) -> bool { 19 | visited[v] = true; 20 | colors[v] = color; 21 | 22 | for w in g.adj_edge(v) { 23 | if !visited[w] { 24 | if !__dfs(g, w, visited, colors, 1 - color) { 25 | return false; 26 | } 27 | } else if colors[w] == colors[v] { 28 | return false; 29 | } 30 | } 31 | 32 | true 33 | } 34 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/src/bipatite_matching.rs: -------------------------------------------------------------------------------- 1 | use crate::{bipartition, graph::Graph, max_flow::MaxFlow, weighted_graph::WeightedGraph}; 2 | 3 | pub struct BipartiteMatching { 4 | g: Graph, 5 | max_matching: usize, 6 | } 7 | 8 | impl BipartiteMatching { 9 | pub fn new(g: Graph) -> Self { 10 | let (is_bd, colors) = bipartition::is_bipartition(&g); 11 | if !is_bd { 12 | panic!("Only works for bipartition graph"); 13 | } 14 | let colors = colors.unwrap(); 15 | 16 | let mut network = WeightedGraph::new(g.v() + 2, true); 17 | for v in 0..g.v() { 18 | if colors[v] == 0 { 19 | network.add_edge(g.v(), v, 1); 20 | } else { 21 | network.add_edge(v, g.v() + 1, 1); 22 | } 23 | for w in g.adj_edge(v) { 24 | if v < w { 25 | if colors[v] == 0 { 26 | network.add_edge(v, w, 1); 27 | } else { 28 | network.add_edge(w, v, 1); 29 | } 30 | } 31 | } 32 | } 33 | 34 | let mf = MaxFlow::new(network, g.v(), g.v() + 1); 35 | let max_matching = mf.maxflow(); 36 | 37 | Self { g, max_matching } 38 | } 39 | 40 | pub fn max_matching(&self) -> usize { 41 | self.max_matching 42 | } 43 | 44 | pub fn is_perfect_matching(&self) -> bool { 45 | self.max_matching * 2 == self.g.v() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/src/main.rs: -------------------------------------------------------------------------------- 1 | use bipatite_matching::BipartiteMatching; 2 | use graph::Graph; 3 | 4 | mod bipartition; 5 | mod bipatite_matching; 6 | mod graph; 7 | mod max_flow; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = Graph::from_file("g.txt"); 12 | let bipatite_matching = BipartiteMatching::new(g); 13 | println!("{}", bipatite_matching.max_matching()); 14 | 15 | let g = Graph::from_file("g2.txt"); 16 | let bipatite_matching = BipartiteMatching::new(g); 17 | println!("{}", bipatite_matching.max_matching()); 18 | } 19 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/03-Solving-Matching-Problem-in-Max-Flow/src/max_flow.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct MaxFlow { 6 | rg: WeightedGraph, 7 | s: usize, 8 | t: usize, 9 | maxflow: usize, 10 | } 11 | 12 | impl MaxFlow { 13 | pub fn new(g: WeightedGraph, s: usize, t: usize) -> Self { 14 | if !g.directed() { 15 | panic!("Only support directed graph"); 16 | } 17 | if g.v() < 2 { 18 | panic!("Graph should has more than one vertex"); 19 | } 20 | g.validate_vertex(s); 21 | g.validate_vertex(t); 22 | 23 | if s == t { 24 | panic!("start vertex can't be the same as end vertex"); 25 | } 26 | 27 | let rg = WeightedGraph::new_rg(&g); 28 | let mut q = VecDeque::new(); 29 | q.push_back(s); 30 | let maxflow = 0; 31 | let mut this = Self { rg, s, t, maxflow }; 32 | 33 | while let Some(path) = this.get_augementing_path() { 34 | let mut f = i32::MAX; 35 | for i in 1..path.len() { 36 | let v = path[i - 1]; 37 | let w = path[i]; 38 | f = i32::min(f, this.rg.get_weight(v, w).unwrap()); 39 | } 40 | this.maxflow += f as usize; 41 | for i in 1..path.len() { 42 | let v = path[i - 1]; 43 | let w = path[i]; 44 | this.rg 45 | .set_weight(v, w, this.rg.get_weight(v, w).unwrap() - f as i32); 46 | this.rg 47 | .set_weight(w, v, this.rg.get_weight(w, v).unwrap() + f as i32); 48 | } 49 | } 50 | 51 | this 52 | } 53 | 54 | fn get_augementing_path(&mut self) -> Option> { 55 | let mut pre = vec![-1; self.rg.v()]; 56 | let mut q = VecDeque::new(); 57 | q.push_back(self.s); 58 | pre[self.s] = self.s as i32; 59 | while let Some(v) = q.pop_front() { 60 | if v == self.t { 61 | break; 62 | } 63 | for w in self.rg.adj_edge(v) { 64 | if pre[w] == -1 && self.rg.get_weight(v, w).unwrap() > 0 { 65 | q.push_back(w); 66 | pre[w] = v as i32; 67 | } 68 | } 69 | } 70 | 71 | if pre[self.t] == -1 { 72 | return None; 73 | } 74 | 75 | let mut res = vec![]; 76 | let mut cur = self.t; 77 | while cur as usize != self.s { 78 | res.push(cur); 79 | cur = pre[cur] as usize; 80 | } 81 | res.push(self.s); 82 | res.reverse(); 83 | Some(res) 84 | } 85 | 86 | pub fn maxflow(&self) -> usize { 87 | self.maxflow 88 | } 89 | 90 | pub fn get_flow(&self, v: usize, w: usize) -> Option { 91 | if self.rg.has_edge(v, w) { 92 | return Some(self.rg.get_weight(w, v).unwrap()); 93 | } 94 | None 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter15-06" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter15-06" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/g.txt: -------------------------------------------------------------------------------- 1 | 8 6 2 | 0 4 3 | 0 6 4 | 1 4 5 | 2 6 6 | 3 5 7 | 3 7 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/g2.txt: -------------------------------------------------------------------------------- 1 | 8 7 2 | 0 4 3 | 0 6 4 | 1 4 5 | 1 7 6 | 2 6 7 | 3 5 8 | 3 7 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/src/bipartition.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | /// `colors`: 表示颜色 4 | /// - 0 -> blue 5 | /// - 1 -> green 6 | pub fn is_bipartition(g: &Graph) -> (bool, Option>) { 7 | let mut visited = vec![false; g.v()]; 8 | let mut colors = vec![-1; g.v()]; 9 | for v in 0..g.v() { 10 | if !visited[v] && !__dfs(g, v, &mut visited, &mut colors, 0) { 11 | return (false, None); 12 | } 13 | } 14 | 15 | (true, Some(colors)) 16 | } 17 | 18 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, colors: &mut Vec, color: i32) -> bool { 19 | visited[v] = true; 20 | colors[v] = color; 21 | 22 | for w in g.adj_edge(v) { 23 | if !visited[w] { 24 | if !__dfs(g, w, visited, colors, 1 - color) { 25 | return false; 26 | } 27 | } else if colors[w] == colors[v] { 28 | return false; 29 | } 30 | } 31 | 32 | true 33 | } 34 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/src/hungarian.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::{bipartition, graph::Graph}; 4 | 5 | pub struct Hungarian { 6 | g: Graph, 7 | max_matching: usize, 8 | matching: Vec, 9 | } 10 | 11 | impl Hungarian { 12 | pub fn new(g: Graph) -> Self { 13 | let (is_bd, colors) = bipartition::is_bipartition(&g); 14 | if !is_bd { 15 | panic!("Only works for bipartition graph"); 16 | } 17 | let colors = colors.unwrap(); 18 | let matching = vec![-1; g.v()]; 19 | let mut this = Self { 20 | g, 21 | max_matching: 0, 22 | matching, 23 | }; 24 | 25 | for v in 0..this.g.v() { 26 | if colors[v] == 0 && this.matching[v] == -1 && this.bfs(v) { 27 | this.max_matching += 1; 28 | } 29 | } 30 | 31 | this 32 | } 33 | 34 | fn bfs(&mut self, v: usize) -> bool { 35 | let mut q = VecDeque::new(); 36 | let mut pre = vec![-1; self.g.v()]; 37 | q.push_back(v); 38 | pre[v] = v as i32; 39 | while let Some(v) = q.pop_front() { 40 | for next in self.g.adj_edge(v) { 41 | if pre[next] != -1 { 42 | continue; 43 | } 44 | if self.matching[next] != -1 { 45 | q.push_back(self.matching[next] as usize); 46 | pre[next] = v as i32; 47 | pre[self.matching[next] as usize] = next as i32; 48 | } else { 49 | pre[next] = v as i32; 50 | let path = Self::get_augementing_path(&pre, v, next); 51 | for i in (0..path.len()).step_by(2) { 52 | self.matching[path[i]] = path[i + 1] as i32; 53 | self.matching[path[i + 1]] = path[i] as i32; 54 | } 55 | return true; // find a path 56 | } 57 | } 58 | } 59 | 60 | false 61 | } 62 | 63 | fn get_augementing_path(pre: &[i32], v: usize, w: usize) -> Vec { 64 | let mut res = Vec::new(); 65 | let mut cur = w; 66 | while cur != v { 67 | res.push(cur); 68 | cur = pre[cur] as usize; 69 | } 70 | res.push(v); 71 | res 72 | } 73 | 74 | pub fn max_matching(&self) -> usize { 75 | self.max_matching 76 | } 77 | 78 | pub fn is_perfect_matching(&self) -> bool { 79 | self.max_matching * 2 == self.g.v() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::hungarian::Hungarian; 2 | use graph::Graph; 3 | 4 | mod bipartition; 5 | mod graph; 6 | mod hungarian; 7 | mod max_flow; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = Graph::from_file("g.txt"); 12 | let hg = Hungarian::new(g); 13 | println!("{}", hg.max_matching()); 14 | 15 | let g = Graph::from_file("g2.txt"); 16 | let hg = Hungarian::new(g); 17 | println!("{}", hg.max_matching()); 18 | } 19 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/06-Hungarian-BFS/src/max_flow.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct MaxFlow { 6 | rg: WeightedGraph, 7 | s: usize, 8 | t: usize, 9 | maxflow: usize, 10 | } 11 | 12 | impl MaxFlow { 13 | pub fn new(g: WeightedGraph, s: usize, t: usize) -> Self { 14 | if !g.directed() { 15 | panic!("Only support directed graph"); 16 | } 17 | if g.v() < 2 { 18 | panic!("Graph should has more than one vertex"); 19 | } 20 | g.validate_vertex(s); 21 | g.validate_vertex(t); 22 | 23 | if s == t { 24 | panic!("start vertex can't be the same as end vertex"); 25 | } 26 | 27 | let rg = WeightedGraph::new_rg(&g); 28 | let mut q = VecDeque::new(); 29 | q.push_back(s); 30 | let maxflow = 0; 31 | let mut this = Self { rg, s, t, maxflow }; 32 | 33 | while let Some(path) = this.get_augementing_path() { 34 | let mut f = i32::MAX; 35 | for i in 1..path.len() { 36 | let v = path[i - 1]; 37 | let w = path[i]; 38 | f = i32::min(f, this.rg.get_weight(v, w).unwrap()); 39 | } 40 | this.maxflow += f as usize; 41 | for i in 1..path.len() { 42 | let v = path[i - 1]; 43 | let w = path[i]; 44 | this.rg 45 | .set_weight(v, w, this.rg.get_weight(v, w).unwrap() - f as i32); 46 | this.rg 47 | .set_weight(w, v, this.rg.get_weight(w, v).unwrap() + f as i32); 48 | } 49 | } 50 | 51 | this 52 | } 53 | 54 | fn get_augementing_path(&mut self) -> Option> { 55 | let mut pre = vec![-1; self.rg.v()]; 56 | let mut q = VecDeque::new(); 57 | q.push_back(self.s); 58 | pre[self.s] = self.s as i32; 59 | while let Some(v) = q.pop_front() { 60 | if v == self.t { 61 | break; 62 | } 63 | for w in self.rg.adj_edge(v) { 64 | if pre[w] == -1 && self.rg.get_weight(v, w).unwrap() > 0 { 65 | q.push_back(w); 66 | pre[w] = v as i32; 67 | } 68 | } 69 | } 70 | 71 | if pre[self.t] == -1 { 72 | return None; 73 | } 74 | 75 | let mut res = vec![]; 76 | let mut cur = self.t; 77 | while cur as usize != self.s { 78 | res.push(cur); 79 | cur = pre[cur] as usize; 80 | } 81 | res.push(self.s); 82 | res.reverse(); 83 | Some(res) 84 | } 85 | 86 | pub fn maxflow(&self) -> usize { 87 | self.maxflow 88 | } 89 | 90 | pub fn get_flow(&self, v: usize, w: usize) -> Option { 91 | if self.rg.has_edge(v, w) { 92 | return Some(self.rg.get_weight(w, v).unwrap()); 93 | } 94 | None 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chapter15-07" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter15-07" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/g.txt: -------------------------------------------------------------------------------- 1 | 8 6 2 | 0 4 3 | 0 6 4 | 1 4 5 | 2 6 6 | 3 5 7 | 3 7 8 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/g2.txt: -------------------------------------------------------------------------------- 1 | 8 7 2 | 0 4 3 | 0 6 4 | 1 4 5 | 1 7 6 | 2 6 7 | 3 5 8 | 3 7 9 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/src/bipartition.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::Graph; 2 | 3 | /// `colors`: 表示颜色 4 | /// - 0 -> blue 5 | /// - 1 -> green 6 | pub fn is_bipartition(g: &Graph) -> (bool, Option>) { 7 | let mut visited = vec![false; g.v()]; 8 | let mut colors = vec![-1; g.v()]; 9 | for v in 0..g.v() { 10 | if !visited[v] && !__dfs(g, v, &mut visited, &mut colors, 0) { 11 | return (false, None); 12 | } 13 | } 14 | 15 | (true, Some(colors)) 16 | } 17 | 18 | fn __dfs(g: &Graph, v: usize, visited: &mut Vec, colors: &mut Vec, color: i32) -> bool { 19 | visited[v] = true; 20 | colors[v] = color; 21 | 22 | for w in g.adj_edge(v) { 23 | if !visited[w] { 24 | if !__dfs(g, w, visited, colors, 1 - color) { 25 | return false; 26 | } 27 | } else if colors[w] == colors[v] { 28 | return false; 29 | } 30 | } 31 | 32 | true 33 | } 34 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/src/hungarian.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::{bipartition, graph::Graph}; 4 | 5 | pub struct Hungarian { 6 | g: Graph, 7 | max_matching: usize, 8 | matching: Vec, 9 | } 10 | 11 | impl Hungarian { 12 | pub fn new(g: Graph) -> Self { 13 | let (is_bd, colors) = bipartition::is_bipartition(&g); 14 | if !is_bd { 15 | panic!("Only works for bipartition graph"); 16 | } 17 | let colors = colors.unwrap(); 18 | let matching = vec![-1; g.v()]; 19 | let mut this = Self { 20 | g, 21 | max_matching: 0, 22 | matching, 23 | }; 24 | 25 | for v in 0..this.g.v() { 26 | if colors[v] == 0 && this.matching[v] == -1 { 27 | let mut visited = vec![false; this.g.v()]; 28 | if this.dfs(v, &mut visited) { 29 | this.max_matching += 1; 30 | } 31 | } 32 | } 33 | 34 | this 35 | } 36 | 37 | fn dfs(&mut self, v: usize, visited: &mut [bool]) -> bool { 38 | visited[v] = true; 39 | for w in self.g.adj_edge(v) { 40 | if visited[w] { 41 | continue; 42 | } 43 | visited[w] = true; 44 | if self.matching[w] == -1 || self.dfs(w, visited) { 45 | self.matching[w] = v as i32; 46 | self.matching[v] = w as i32; 47 | return true; 48 | } 49 | } 50 | 51 | false 52 | } 53 | 54 | fn get_augementing_path(pre: &[i32], v: usize, w: usize) -> Vec { 55 | let mut res = Vec::new(); 56 | let mut cur = w; 57 | while cur != v { 58 | res.push(cur); 59 | cur = pre[cur] as usize; 60 | } 61 | res.push(v); 62 | res 63 | } 64 | 65 | pub fn max_matching(&self) -> usize { 66 | self.max_matching 67 | } 68 | 69 | pub fn is_perfect_matching(&self) -> bool { 70 | self.max_matching * 2 == self.g.v() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::hungarian::Hungarian; 2 | use graph::Graph; 3 | 4 | mod bipartition; 5 | mod graph; 6 | mod hungarian; 7 | mod max_flow; 8 | mod weighted_graph; 9 | 10 | fn main() { 11 | let g = Graph::from_file("g.txt"); 12 | let hg = Hungarian::new(g); 13 | println!("{}", hg.max_matching()); 14 | 15 | let g = Graph::from_file("g2.txt"); 16 | let hg = Hungarian::new(g); 17 | println!("{}", hg.max_matching()); 18 | } 19 | -------------------------------------------------------------------------------- /15-Matching-Algorithm/07-Hungarian-DFS/src/max_flow.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use crate::weighted_graph::WeightedGraph; 4 | 5 | pub struct MaxFlow { 6 | rg: WeightedGraph, 7 | s: usize, 8 | t: usize, 9 | maxflow: usize, 10 | } 11 | 12 | impl MaxFlow { 13 | pub fn new(g: WeightedGraph, s: usize, t: usize) -> Self { 14 | if !g.directed() { 15 | panic!("Only support directed graph"); 16 | } 17 | if g.v() < 2 { 18 | panic!("Graph should has more than one vertex"); 19 | } 20 | g.validate_vertex(s); 21 | g.validate_vertex(t); 22 | 23 | if s == t { 24 | panic!("start vertex can't be the same as end vertex"); 25 | } 26 | 27 | let rg = WeightedGraph::new_rg(&g); 28 | let mut q = VecDeque::new(); 29 | q.push_back(s); 30 | let maxflow = 0; 31 | let mut this = Self { rg, s, t, maxflow }; 32 | 33 | while let Some(path) = this.get_augementing_path() { 34 | let mut f = i32::MAX; 35 | for i in 1..path.len() { 36 | let v = path[i - 1]; 37 | let w = path[i]; 38 | f = i32::min(f, this.rg.get_weight(v, w).unwrap()); 39 | } 40 | this.maxflow += f as usize; 41 | for i in 1..path.len() { 42 | let v = path[i - 1]; 43 | let w = path[i]; 44 | this.rg 45 | .set_weight(v, w, this.rg.get_weight(v, w).unwrap() - f as i32); 46 | this.rg 47 | .set_weight(w, v, this.rg.get_weight(w, v).unwrap() + f as i32); 48 | } 49 | } 50 | 51 | this 52 | } 53 | 54 | fn get_augementing_path(&mut self) -> Option> { 55 | let mut pre = vec![-1; self.rg.v()]; 56 | let mut q = VecDeque::new(); 57 | q.push_back(self.s); 58 | pre[self.s] = self.s as i32; 59 | while let Some(v) = q.pop_front() { 60 | if v == self.t { 61 | break; 62 | } 63 | for w in self.rg.adj_edge(v) { 64 | if pre[w] == -1 && self.rg.get_weight(v, w).unwrap() > 0 { 65 | q.push_back(w); 66 | pre[w] = v as i32; 67 | } 68 | } 69 | } 70 | 71 | if pre[self.t] == -1 { 72 | return None; 73 | } 74 | 75 | let mut res = vec![]; 76 | let mut cur = self.t; 77 | while cur as usize != self.s { 78 | res.push(cur); 79 | cur = pre[cur] as usize; 80 | } 81 | res.push(self.s); 82 | res.reverse(); 83 | Some(res) 84 | } 85 | 86 | pub fn maxflow(&self) -> usize { 87 | self.maxflow 88 | } 89 | 90 | pub fn get_flow(&self, v: usize, w: usize) -> Option { 91 | if self.rg.has_edge(v, w) { 92 | return Some(self.rg.get_weight(w, v).unwrap()); 93 | } 94 | None 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Zhang Jing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | --------------------------------------------------------------------------------