▶ 书中第四章部分程序,包括在加上自己补充的代码,二分图的判定和染色
● 二分图 1
1 //+----------------------------------------------------------------------------- 2 // 第四章,二分图 3 package package01; 4 5 import edu.princeton.cs.algs4.StdOut; 6 import edu.princeton.cs.algs4.StdRandom; 7 import edu.princeton.cs.algs4.GraphGenerator; 8 import edu.princeton.cs.algs4.Graph; 9 import edu.princeton.cs.algs4.Stack; 10 11 public class class01 12 { 13 private boolean isBipartite; 14 private boolean[] color; // 顶点染色情况 15 private boolean[] marked; 16 private int[] edgeTo; 17 private Stack<Integer> cycle; // odd-length cycle 18 19 public class01(Graph G) 20 { 21 isBipartite = true; 22 color = new boolean[G.V()]; 23 marked = new boolean[G.V()]; 24 edgeTo = new int[G.V()]; 25 for (int v = 0; v < G.V(); v++)// 逐顶点深度优先遍历 26 { 27 if (!marked[v]) 28 { 29 dfs(G, v); 30 } 31 } 32 } 33 34 private void dfs(Graph G, int v) 35 { 36 marked[v] = true; 37 for (int w : G.adj(v)) 38 { 39 if (cycle != null) // 已经有奇数环,停止递归 40 return; 41 if (!marked[w]) // 正常的标记、染色、继续递归 42 { 43 edgeTo[w] = v; 44 color[w] = !color[v]; 45 dfs(G, w); 46 } 47 else if (color[w] == color[v]) // v ~ w 形成了长度为奇数的环 48 { 49 isBipartite = false; 50 cycle = new Stack<Integer>(); 51 for (int x = v; x != w; x = edgeTo[x]) // 把从 v 到 w 的顶点压栈,保存有问题的环部分 52 cycle.push(x); 53 cycle.push(w); 54 } 55 } 56 } 57 58 public boolean isBipartite() 59 { 60 return isBipartite; 61 } 62 63 public boolean color(int v) 64 { 65 if (!isBipartite) 66 throw new UnsupportedOperationException("\n<color> Graph is not bipartite.\n"); 67 return color[v]; 68 } 69 70 public Iterable<Integer> oddCycle() 71 { 72 return cycle; 73 } 74 75 public static void main(String[] args) 76 { 77 int V1 = Integer.parseInt(args[0]); // 生成 G(V1 + V2, E) 顶点的二分图,再随机添加 F 条边 78 int V2 = Integer.parseInt(args[1]); 79 int E = Integer.parseInt(args[2]); 80 int F = Integer.parseInt(args[3]); 81 82 Graph G = GraphGenerator.bipartite(V1, V2, E); 83 for (int i = 0; i < F; i++) 84 { 85 int v = StdRandom.uniform(V1 + V2); 86 int w = StdRandom.uniform(V1 + V2); 87 G.addEdge(v, w); 88 } 89 StdOut.println(G); 90 91 class01 b = new class01(G); 92 if (b.isBipartite()) 93 { 94 StdOut.println("Graph is bipartite"); 95 for (int v = 0; v < G.V(); v++) 96 StdOut.println(v + ": " + b.color(v)); 97 } 98 else 99 { 100 StdOut.print("Graph has an odd-length cycle: "); 101 for (int x : b.oddCycle()) 102 StdOut.print(x + " "); 103 StdOut.println(); 104 } 105 } 106 }
● 二分图 2
1 package package01; 2 3 import edu.princeton.cs.algs4.StdOut; 4 import edu.princeton.cs.algs4.StdRandom; 5 import edu.princeton.cs.algs4.GraphGenerator; 6 import edu.princeton.cs.algs4.Graph; 7 import edu.princeton.cs.algs4.Stack; 8 import edu.princeton.cs.algs4.Queue; 9 10 public class class01 11 { 12 private boolean isBipartite; // 是否为二分图 13 private boolean[] color; // 顶点染色 14 private boolean[] marked; 15 private int[] edgeTo; 16 private Queue<Integer> cycle; // 存储了奇数长度的环(二分图则队列为空) 17 18 public class01(Graph G) 19 { 20 isBipartite = true; 21 color = new boolean[G.V()]; 22 marked = new boolean[G.V()]; 23 edgeTo = new int[G.V()]; 24 for (int v = 0; v < G.V() && isBipartite; v++) 25 { 26 if (!marked[v]) 27 bfs(G, v); // 广度优先遍历 28 } 29 } 30 31 private void bfs(Graph G, int s) 32 { 33 Queue<Integer> q = new Queue<Integer>(); 34 color[s] = false; // 颜色使用 true / false 35 marked[s] = true; 36 for (q.enqueue(s); !q.isEmpty();) 37 { 38 int v = q.dequeue(); 39 for (int w : G.adj(v)) 40 if (!marked[w]) 41 { 42 marked[w] = true; 43 edgeTo[w] = v; 44 color[w] = !color[v]; 45 q.enqueue(w); 46 } 47 else if (color[w] == color[v]) // w 已经遍历过,且形成了奇数长度的环 48 { 49 isBipartite = false; 50 cycle = new Queue<Integer>(); 51 Stack<Integer> stack = new Stack<Integer>(); 52 int x = v, y = w; // 两端同时向回走,color[v] == color[w] 于是 color[x] == color[y] 53 for (; x != y; x = edgeTo[x], y = edgeTo[y]) // 存在节点 z 使得 edgeTo[x] == edgeTo[y] == z,循环结束时 x 和 y 均指向公共顶点 z 54 { 55 stack.push(x); 56 cycle.enqueue(y); 57 } 58 for (stack.push(x); !stack.isEmpty(); cycle.enqueue(stack.pop())); // 公共顶点 z 压栈,然后吐栈拼入队列,多一步是防止本来栈空 59 cycle.enqueue(w); 60 return; 61 } 62 } 63 } 64 65 public boolean isBipartite() 66 { 67 return isBipartite; 68 } 69 70 public boolean color(int v) 71 { 72 if (!isBipartite) 73 throw new UnsupportedOperationException("\n<color> Graph is not bipartite.\n"); 74 return color[v]; 75 } 76 77 public Iterable<Integer> oddCycle() 78 { 79 return cycle; 80 } 81 82 public static void main(String[] args) 83 { 84 int V1 = Integer.parseInt(args[0]); 85 int V2 = Integer.parseInt(args[1]); 86 int E = Integer.parseInt(args[2]); 87 int F = Integer.parseInt(args[3]); 88 Graph G = GraphGenerator.bipartite(V1, V2, E); 89 for (int i = 0; i < F; i++) 90 { 91 int v = StdRandom.uniform(V1 + V2); 92 int w = StdRandom.uniform(V1 + V2); 93 G.addEdge(v, w); 94 } 95 StdOut.println(G); 96 97 class01 b = new class01(G); 98 if (b.isBipartite()) 99 { 100 StdOut.println("Graph is bipartite"); 101 for (int v = 0; v < G.V(); v++) 102 StdOut.println(v + ": " + b.color(v)); 103 } 104 else 105 { 106 StdOut.print("Graph has an odd-length cycle: "); 107 for (int x : b.oddCycle()) 108 StdOut.print(x + " "); 109 StdOut.println(); 110 } 111 } 112 }