《算法》第四章部分程序 part 3

▶ 书中第四章部分程序,加上自己补充的代码,随机生成各类有向图

● 随机生成有向图

  1 package package01;
  2 
  3 import edu.princeton.cs.algs4.StdOut;
  4 import edu.princeton.cs.algs4.Digraph;                  // 多了有向图,少了集合
  5 import edu.princeton.cs.algs4.SET;
  6 import edu.princeton.cs.algs4.StdRandom;
  7 
  8 public class class01
  9 {
 10     private static final class Edge implements Comparable<Edge>
 11     {
 12         private final int v;
 13         private final int w;
 14 
 15         private Edge(int v1, int v2)
 16         {
 17             if (v1 < v2)
 18             {
 19                 v = v1;
 20                 w = v2;
 21             }
 22             else
 23             {
 24                 v = v2;
 25                 w = v1;
 26             }
 27         }
 28 
 29         public int compareTo(Edge that)
 30         {
 31             if (v < that.v)
 32                 return -1;
 33             if (v > that.v)
 34                 return +1;
 35             if (w < that.w)
 36                 return -1;
 37             if (w > that.w)
 38                 return +1;
 39             return 0;
 40         }
 41     }
 42 
 43     private class01() {}
 44 
 45     public static Digraph simple(int V, int E)
 46     {
 47         if (E < 0 || E >(long) V*(V - 1) / 2)
 48             throw new IllegalArgumentException("
<simple> E < 0 || E > V(V-1)/2.
");
 49         Digraph G = new Digraph(V);
 50         SET<Edge> set = new SET<Edge>();
 51         for (; G.E() < E;)
 52         {
 53             int v = StdRandom.uniform(V);
 54             int w = StdRandom.uniform(V);
 55             Edge e = new Edge(v, w);
 56             if ((v != w) && !set.contains(e))
 57             {
 58                 set.add(e);
 59                 G.addEdge(v, w);
 60             }
 61         }
 62         return G;
 63     }
 64 
 65     public static Digraph simple(int V, double p)
 66     {
 67         if (p < 0.0 || p > 1.0)
 68             throw new IllegalArgumentException("
<simple> p < 0.0 || p > 1.0.
");
 69         Digraph G = new Digraph(V);
 70         for (int v = 0; v < V; v++)
 71         {
 72             for (int w = 0; w < V; w++)                 // 从0 开始
 73             {
 74                 if (v != w && StdRandom.bernoulli(p))   // 去掉自环
 75                     G.addEdge(v, w);
 76             }
 77         }
 78         return G;
 79     }
 80 
 81     public static Digraph complete(int V)
 82     {
 83         return simple(V, 1.0);
 84     }
 85 
 86     public static Digraph dag(int V, int E)             //(非均匀地)生成指定定点数和边数的有向无环图(Directed Acyclic Graph)
 87     {
 88         if (E < 0 || E >(long) V*(V - 1) / 2)
 89             throw new IllegalArgumentException("
<dag> E < 0 || E > V1*V2.
");
 90         int[] vertices = new int[V];
 91         for (int i = 0; i < V; i++)
 92             vertices[i] = i;
 93         StdRandom.shuffle(vertices);
 94         Digraph G = new Digraph(V);
 95         SET<Edge> set = new SET<Edge>();
 96         for (; G.E() < E;)
 97         {
 98             int i = StdRandom.uniform(V);
 99             int j = StdRandom.uniform(V);
100             Edge e = new Edge(i, j);
101             if (i < j && !set.contains(e))              // 限定从索引较小的顶点指向索引较大的顶点
102             {
103                 set.add(e);
104                 G.addEdge(vertices[i], vertices[j]);
105             }
106         }
107         return G;
108     }
109 
110     public static Digraph tournament(int V)             // 生成竞赛图(任意两顶点间有一条有向边)
111     {
112         Digraph G = new Digraph(V);
113         for (int v = 0; v < G.V(); v++)
114         {
115             for (int w = v + 1; w < G.V(); w++)
116             {
117                 if (StdRandom.bernoulli(0.5))
118                     G.addEdge(v, w);
119                 else
120                     G.addEdge(w, v);
121             }
122         }
123         return G;
124     }
125 
126     public static Digraph rootedInDAG(int V, int E)     // 生成有入根 DAG 图(所有链有共同的终点)
127     {
128         if (E < V - 1 || E >(long) V*(V - 1) / 2)
129             throw new IllegalArgumentException("
<rootedInDAG> E < 0 || E > V1*V2.
");
130         int[] vertices = new int[V];
131         for (int i = 0; i < V; i++)
132             vertices[i] = i;
133         StdRandom.shuffle(vertices);
134         Digraph G = new Digraph(V);
135         SET<Edge> set = new SET<Edge>();
136         for (int v = 0; v < V - 1; v++)                 // 每个点连接到索引更靠后的一个顶点上,保证每条链都收敛到最后一个顶点
137         {
138             int w = StdRandom.uniform(v + 1, V);
139             Edge e = new Edge(v, w);
140             set.add(e);
141             G.addEdge(vertices[v], vertices[w]);
142         }
143         for (; G.E() < E;)                              // 按靠后规则添加剩余的的边
144         {
145             int v = StdRandom.uniform(V);
146             int w = StdRandom.uniform(V);
147             Edge e = new Edge(v, w);
148             if ((v < w) && !set.contains(e))
149             {
150                 set.add(e);
151                 G.addEdge(vertices[v], vertices[w]);
152             }
153         }
154         return G;
155     }
156 
157     public static Digraph rootedOutDAG(int V, int E)    // 生成有出根 DAG 图(所有链有相同的起点)
158     {
159         if (E < V - 1 || E >(long) V*(V - 1) / 2)
160             throw new IllegalArgumentException("
<rootedOutDAG> E < 0 || E > V1*V2.
");
161         int[] vertices = new int[V];
162         for (int i = 0; i < V; i++)
163             vertices[i] = i;
164         StdRandom.shuffle(vertices);
165         Digraph G = new Digraph(V);
166         SET<Edge> set = new SET<Edge>();
167         for (int v = 0; v < V - 1; v++)
168         {
169             int w = StdRandom.uniform(v + 1, V);
170             Edge e = new Edge(w, v);                    // 就是把 rootedInDAG 中出现 (v,w) 的地方全部换成 (v,w) 即可
171             set.add(e);
172             G.addEdge(vertices[w], vertices[v]);        //
173         }
174         for (; G.E() < E;)
175         {
176             int v = StdRandom.uniform(V);
177             int w = StdRandom.uniform(V);
178             Edge e = new Edge(w, v);                    //
179             if ((v < w) && !set.contains(e))
180             {
181                 set.add(e);
182                 G.addEdge(vertices[w], vertices[v]);    //
183             }
184         }
185         return G;
186     }
187 
188     public static Digraph rootedInTree(int V)           // 生成有入根树,在 rootedInDAG 的基础上限定了边数
189     {
190         return rootedInDAG(V, V - 1);
191     }
192 
193     public static Digraph rootedOutTree(int V)          // 生成有出根树,在 rootedOutDAG 的基础上限定了边数
194     {
195         return rootedOutDAG(V, V - 1);
196     }
197 
198     public static Digraph path(int V)                   // 路径图,同无向版本
199     {
200         int[] vertices = new int[V];
201         for (int i = 0; i < V; i++)
202             vertices[i] = i;
203         StdRandom.shuffle(vertices);
204         Digraph G = new Digraph(V);
205         for (int i = 0; i < V - 1; i++)
206             G.addEdge(vertices[i], vertices[i + 1]);
207         return G;
208     }
209 
210     public static Digraph binaryTree(int V)             // 二叉树,同无向版本
211     {
212         int[] vertices = new int[V];
213         for (int i = 0; i < V; i++)
214             vertices[i] = i;
215         StdRandom.shuffle(vertices);
216         Digraph G = new Digraph(V);
217         for (int i = 1; i < V; i++)
218             G.addEdge(vertices[i], vertices[(i - 1) / 2]);
219         return G;
220     }
221 
222     public static Digraph cycle(int V)                  // 环,同无向版本
223     {
224         int[] vertices = new int[V];
225         for (int i = 0; i < V; i++)
226             vertices[i] = i;
227         StdRandom.shuffle(vertices);
228         Digraph G = new Digraph(V);
229         for (int i = 0; i < V - 1; i++)
230             G.addEdge(vertices[i], vertices[i + 1]);
231         G.addEdge(vertices[V - 1], vertices[0]);
232         return G;
233     }
234 
235     public static Digraph eulerianCycle(int V, int E)   // 欧拉回路,同无向版本
236     {
237         if (E <= 0 || V <= 0)
238             throw new IllegalArgumentException("
<eulerianCycle> E <= 0 || V <= 0.
");
239         int[] node = new int[E];
240         for (int i = 0; i < E; i++)
241             node[i] = StdRandom.uniform(V);
242         Digraph G = new Digraph(V);
243         for (int i = 0; i < E - 1; i++)
244             G.addEdge(node[i], node[i + 1]);
245         G.addEdge(node[E - 1], node[0]);
246         return G;
247     }
248 
249     public static Digraph eulerianPath(int V, int E)    // 欧拉路径,同无向版本
250     {
251         if (E <= 0 || V <= 0)
252             throw new IllegalArgumentException("
<eulerianPath> E <= 0 || V <= 0.
");
253         int[] node = new int[E + 1];
254         for (int i = 0; i < E + 1; i++)
255             node[i] = StdRandom.uniform(V);
256         Digraph G = new Digraph(V);
257         for (int i = 0; i < E; i++)
258             G.addEdge(node[i], node[i + 1]);
259         return G;
260     }
261 
262     public static Digraph strong(int V, int E, int c)   // 生成指定定点数、边数、强连通分量上限数的有向图
263     {
264         if (E <= 2 * (V - c) || E >(long) V*(V - 1) / 2 || c >= V || c <= 0)
265             throw new IllegalArgumentException("
<strong> E <= 2 * (V - c) || E > (long) V*(V - 1) / 2 || c >= V || c <= 0.
");
266 
267         Digraph G = new Digraph(V);
268         SET<Edge> set = new SET<Edge>();
269 
270         int[] label = new int[V];                       // 给每个顶点一个连通分量的标号
271         for (int v = 0; v < V; v++)
272             label[v] = StdRandom.uniform(c);
273         for (int i = 0; i < c; i++)                     // 遍历每个分量,分别生成强连通图
274         {                                               // 原理是每个分量中挑一个根点,生成关于该点的入根树和出根树,则分量内所有顶点能以该根点为中继进行连通
275             int count = 0;                              // 该分量的顶点数
276             for (int v = 0; v < G.V(); v++)
277             {
278                 if (label[v] == i)
279                     count++;
280             }
281             int[] node = new int[count];                // 在 count 范围内用乱序数组生成子图
282             int j = 0;
283             for (int v = 0; v < V; v++)                 // 选出标号为 i 的所有顶点的编号
284             {
285                 if (label[v] == i)
286                     node[j++] = v;
287             }
288             StdRandom.shuffle(node);
289             for (int v = 0; v < count - 1; v++)         // 生成一棵有入根树,根为 node[count-1]
290             {
291                 int w = StdRandom.uniform(v + 1, count);
292                 Edge e = new Edge(w, v);
293                 set.add(e);
294                 G.addEdge(node[w], node[v]);
295             }
296             for (int v = 0; v < count - 1; v++)         // 生成一棵有出根树,根为 node[count-1]
297             {
298                 int w = StdRandom.uniform(v + 1, count);
299                 Edge e = new Edge(v, w);
300                 set.add(e);
301                 G.addEdge(node[v], node[w]);
302             }
303         }
304 
305         for (; G.E() < E;)                              // 添加剩余边
306         {
307             int v = StdRandom.uniform(V);
308             int w = StdRandom.uniform(V);
309             Edge e = new Edge(v, w);
310             if (!set.contains(e) && v != w && label[v] <= label[w]) // 限制顶点的索引范围,防止出现环
311             {
312                 set.add(e);
313                 G.addEdge(v, w);
314             }
315         }
316         return G;
317     }
318 
319     public static void main(String[] args)
320     {
321         int V = Integer.parseInt(args[0]);
322         int E = Integer.parseInt(args[1]);
323 
324         StdOut.println("simple");
325         StdOut.println(simple(V, E));
326 
327         StdOut.println("Erdos-Renyi");
328         double p = (double)E / (V*(V - 1) / 2.0);
329         StdOut.println(simple(V, p));
330 
331         StdOut.println("complete graph");
332         StdOut.println(complete(V));
333 
334         StdOut.println("DAG");
335         StdOut.println(dag(V, E));
336 
337         StdOut.println("tournament");
338         StdOut.println(tournament(V));
339 
340         StdOut.println("rooted-in DAG");
341         StdOut.println(rootedInDAG(V, E));
342 
343         StdOut.println("rooted-out DAG");
344         StdOut.println(rootedOutDAG(V, E));
345 
346         StdOut.println("rooted-in tree");
347         StdOut.println(rootedInTree(V));
348 
349         StdOut.println("rooted-out DAG");
350         StdOut.println(rootedOutTree(V));
351 
352         StdOut.println("path");
353         StdOut.println(path(V));
354 
355         StdOut.println("binary tree");
356         StdOut.println(binaryTree(V));
357 
358         StdOut.println("cycle");
359         StdOut.println(cycle(V));
360 
361         StdOut.println("eulierian cycle");
362         StdOut.println(eulerianCycle(V, E));
363 
364         StdOut.println("eulierian path");
365         StdOut.println(eulerianPath(V, E));
366 
367         StdOut.println("strong");
368         StdOut.println(strong(V, E, 4));
369     }
370 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9807769.html