Graph Theory
1.1 Graph Construction
1.1.1 Adjacency List with Edge Weights
import java.util.ArrayList;import java.util.List;import java.util.Scanner;public class Main { // Define the adjacency list representation of the graph static List<int[]>[] g; // Number of nodes static int n; // Array to store some state or result static int[] f; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // Read the number of nodes n = scanner.nextInt(); // Initialize the adjacency list g = new ArrayList[n + 1]; for (int i = 1; i <= n; i++) { g[i] = new ArrayList<>(); } // Initialize the state array f = new int[n + 1]; // Read the edges and construct the graph for (int i = 1; i < n; i++) { int a = scanner.nextInt(); // One endpoint of the edge int b = scanner.nextInt(); // The other endpoint of the edge int c = scanner.nextInt(); // The weight of the edge // Add the undirected edge to the adjacency list g[a].add(new int[]{b, c}); g[b].add(new int[]{a, c}); } } // Depth-first search (DFS) to traverse the graph static void dfs(int u, int fa) { // Traverse all adjacent nodes of node u for (int[] pair : g[u]) { int x = pair[0]; // Adjacent node int w = pair[1]; // Weight of the edge // If the adjacent node is the parent node, skip it (to avoid going back) if (x == fa) continue; // Recursively traverse the adjacent nodes dfs(x, u); // Additional logic can be added here } }}
1.1.2 Adjacency List with Node Weights
import java.util.Scanner;import java.util.ArrayList;public class Main { // Define a constant N for the maximum number of nodes static final int N = 100010; // Used to store the adjacency list representation of the graph static ArrayList<Integer>[] g = new ArrayList[N]; // Used to store the weights of the nodes static int[] w = new int[N]; // Depth-first search (DFS) to traverse the graph static void dfs(int u, int fa) { // Handle the operations for node u // Traverse all adjacent nodes of node u for (int x : g[u]) { // If the adjacent node is the parent node, skip it (to avoid going back) if (x == fa) continue; // Recursively traverse the adjacent nodes dfs(x, u); // Handle the operations after returning from the child node } } public static void main(String[] args) { int n, m; Scanner scanner = new Scanner(System.in); // Read the number of nodes n and the number of edges m n = scanner.nextInt(); m = scanner.nextInt(); // Initialize the adjacency list for (int i = 1; i <= n; i++) { g[i] = new ArrayList<>(); } // Read the edges and construct the graph for (int i = 0; i < m; i++) { int a, b; a = scanner.nextInt(); b = scanner.nextInt(); g[a].add(b); // Add an edge from a to b } // Read the weight of each node for (int i = 1; i <= n; i++) { w[i] = scanner.nextInt(); } // DFS can be called here, for example, starting from node 1 // dfs(1, -1); }}
1.1.3 Discretization for Graph Construction
Points have a very large range (e.g., [−109, 109]) or contain negative points. Points are not numbers but strings, and there is a conversion relationship between the strings.
import java.util.*;public class Main { public static void main(String[] args) { // Define a constant N for the possible maximum number of nodes int N = 100010; // Define a hash table to store the edges and their weights between nodes // The key is the node, the value is a list containing the target nodes and edge weights Map<Integer, List<Map.Entry<Integer, Integer>>> path = new HashMap<>(); // Example: Add an edge from node u to node v with a weight of w int u = 1, v = 2, w = 3; // If the hash table does not contain the key u, initialize its value to a new ArrayList if (!path.containsKey(u)) { path.put(u, new ArrayList<>()); } // Add the edge (v, w) to the list of node u path.get(u).add(new AbstractMap.SimpleEntry<>(v, w)); // Example: Traverse all adjacent nodes and edge weights of node int node = 1; // If the hash table contains the key node, traverse it if (path.containsKey(node)) { for (Map.Entry<Integer, Integer> entry : path.get(node)) { int target = entry.getKey(); // Adjacent node int weight = entry.getValue(); // Weight of the edge // Process, for example, print or other logic System.out.println("The edge weight from node " + node + " to node " + target + " is " + weight); } } }}
1.2 Topological Sorting
Used to determine if there is a cycle in a directed graph.
LeetCode 207. Course Schedule
Topological sorting template problem.
Build a graph based on dependencies: if course a
must be taken before course b
, then there is a directed edge b->a
. If all courses can be completed, it means a topological order exists.
import java.util.*;class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { // Create an adjacency list representation of the graph List<List<Integer>> g = new ArrayList<>(); for (int i = 0; i < numCourses; i++) { g.add(new ArrayList<>()); // Initialize adjacency list for each node } // Create an array to store the in-degree of each node int[] d = new int[numCourses]; // Build the graph and calculate the in-degree of each node for (int[] p : prerequisites) { g.get(p[1]).add(p[0]); // Add an edge from node p[1] to node p[0] d[p[0]]++; // Increment the in-degree of node p[0] } // Initialize a queue for BFS Queue<Integer> q = new LinkedList<>(); int cnt = 0; // Counter to record the number of nodes that can be traversed // Add all nodes with in-degree 0 to the queue for (int i = 0; i < numCourses; i++) { if (d[i] == 0) { q.offer(i); cnt++; } } // Perform BFS to process nodes while (!q.isEmpty()) { int t = q.poll(); // Remove a node from the queue for (int v : g.get(t)) { // Traverse all nodes dependent on node t d[v]--; // Decrement the in-degree of the dependent node if (d[v] == 0) { // If the in-degree of the dependent node becomes 0, add it to the queue q.offer(v); cnt++; } } } // If the number of processed nodes equals the total number of nodes, it means all nodes can be traversed; otherwise, they cannot return cnt == numCourses; }}