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

● 随机生成有向图

 package package01;

 import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Digraph; // 多了有向图,少了集合
import edu.princeton.cs.algs4.SET;
import edu.princeton.cs.algs4.StdRandom; public class class01
{
private static final class Edge implements Comparable<Edge>
{
private final int v;
private final int w; private Edge(int v1, int v2)
{
if (v1 < v2)
{
v = v1;
w = v2;
}
else
{
v = v2;
w = v1;
}
} public int compareTo(Edge that)
{
if (v < that.v)
return -1;
if (v > that.v)
return +1;
if (w < that.w)
return -1;
if (w > that.w)
return +1;
return 0;
}
} private class01() {} public static Digraph simple(int V, int E)
{
if (E < 0 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<simple> E < 0 || E > V(V-1)/2.\n");
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (; G.E() < E;)
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if ((v != w) && !set.contains(e))
{
set.add(e);
G.addEdge(v, w);
}
}
return G;
} public static Digraph simple(int V, double p)
{
if (p < 0.0 || p > 1.0)
throw new IllegalArgumentException("\n<simple> p < 0.0 || p > 1.0.\n");
Digraph G = new Digraph(V);
for (int v = 0; v < V; v++)
{
for (int w = 0; w < V; w++) // 从0 开始
{
if (v != w && StdRandom.bernoulli(p)) // 去掉自环
G.addEdge(v, w);
}
}
return G;
} public static Digraph complete(int V)
{
return simple(V, 1.0);
} public static Digraph dag(int V, int E) //(非均匀地)生成指定定点数和边数的有向无环图(Directed Acyclic Graph)
{
if (E < 0 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<dag> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (; G.E() < E;)
{
int i = StdRandom.uniform(V);
int j = StdRandom.uniform(V);
Edge e = new Edge(i, j);
if (i < j && !set.contains(e)) // 限定从索引较小的顶点指向索引较大的顶点
{
set.add(e);
G.addEdge(vertices[i], vertices[j]);
}
}
return G;
} public static Digraph tournament(int V) // 生成竞赛图(任意两顶点间有一条有向边)
{
Digraph G = new Digraph(V);
for (int v = 0; v < G.V(); v++)
{
for (int w = v + 1; w < G.V(); w++)
{
if (StdRandom.bernoulli(0.5))
G.addEdge(v, w);
else
G.addEdge(w, v);
}
}
return G;
} public static Digraph rootedInDAG(int V, int E) // 生成有入根 DAG 图(所有链有共同的终点)
{
if (E < V - 1 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<rootedInDAG> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (int v = 0; v < V - 1; v++) // 每个点连接到索引更靠后的一个顶点上,保证每条链都收敛到最后一个顶点
{
int w = StdRandom.uniform(v + 1, V);
Edge e = new Edge(v, w);
set.add(e);
G.addEdge(vertices[v], vertices[w]);
}
for (; G.E() < E;) // 按靠后规则添加剩余的的边
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if ((v < w) && !set.contains(e))
{
set.add(e);
G.addEdge(vertices[v], vertices[w]);
}
}
return G;
} public static Digraph rootedOutDAG(int V, int E) // 生成有出根 DAG 图(所有链有相同的起点)
{
if (E < V - 1 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<rootedOutDAG> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (int v = 0; v < V - 1; v++)
{
int w = StdRandom.uniform(v + 1, V);
Edge e = new Edge(w, v); // 就是把 rootedInDAG 中出现 (v,w) 的地方全部换成 (v,w) 即可
set.add(e);
G.addEdge(vertices[w], vertices[v]); //换
}
for (; G.E() < E;)
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(w, v); // 换
if ((v < w) && !set.contains(e))
{
set.add(e);
G.addEdge(vertices[w], vertices[v]); // 换
}
}
return G;
} public static Digraph rootedInTree(int V) // 生成有入根树,在 rootedInDAG 的基础上限定了边数
{
return rootedInDAG(V, V - 1);
} public static Digraph rootedOutTree(int V) // 生成有出根树,在 rootedOutDAG 的基础上限定了边数
{
return rootedOutDAG(V, V - 1);
} public static Digraph path(int V) // 路径图,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 0; i < V - 1; i++)
G.addEdge(vertices[i], vertices[i + 1]);
return G;
} public static Digraph binaryTree(int V) // 二叉树,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 1; i < V; i++)
G.addEdge(vertices[i], vertices[(i - 1) / 2]);
return G;
} public static Digraph cycle(int V) // 环,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 0; i < V - 1; i++)
G.addEdge(vertices[i], vertices[i + 1]);
G.addEdge(vertices[V - 1], vertices[0]);
return G;
} public static Digraph eulerianCycle(int V, int E) // 欧拉回路,同无向版本
{
if (E <= 0 || V <= 0)
throw new IllegalArgumentException("\n<eulerianCycle> E <= 0 || V <= 0.\n");
int[] node = new int[E];
for (int i = 0; i < E; i++)
node[i] = StdRandom.uniform(V);
Digraph G = new Digraph(V);
for (int i = 0; i < E - 1; i++)
G.addEdge(node[i], node[i + 1]);
G.addEdge(node[E - 1], node[0]);
return G;
} public static Digraph eulerianPath(int V, int E) // 欧拉路径,同无向版本
{
if (E <= 0 || V <= 0)
throw new IllegalArgumentException("\n<eulerianPath> E <= 0 || V <= 0.\n");
int[] node = new int[E + 1];
for (int i = 0; i < E + 1; i++)
node[i] = StdRandom.uniform(V);
Digraph G = new Digraph(V);
for (int i = 0; i < E; i++)
G.addEdge(node[i], node[i + 1]);
return G;
} public static Digraph strong(int V, int E, int c) // 生成指定定点数、边数、强连通分量上限数的有向图
{
if (E <= 2 * (V - c) || E >(long) V*(V - 1) / 2 || c >= V || c <= 0)
throw new IllegalArgumentException("\n<strong> E <= 2 * (V - c) || E > (long) V*(V - 1) / 2 || c >= V || c <= 0.\n"); Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>(); int[] label = new int[V]; // 给每个顶点一个连通分量的标号
for (int v = 0; v < V; v++)
label[v] = StdRandom.uniform(c);
for (int i = 0; i < c; i++) // 遍历每个分量,分别生成强连通图
{ // 原理是每个分量中挑一个根点,生成关于该点的入根树和出根树,则分量内所有顶点能以该根点为中继进行连通
int count = 0; // 该分量的顶点数
for (int v = 0; v < G.V(); v++)
{
if (label[v] == i)
count++;
}
int[] node = new int[count]; // 在 count 范围内用乱序数组生成子图
int j = 0;
for (int v = 0; v < V; v++) // 选出标号为 i 的所有顶点的编号
{
if (label[v] == i)
node[j++] = v;
}
StdRandom.shuffle(node);
for (int v = 0; v < count - 1; v++) // 生成一棵有入根树,根为 node[count-1]
{
int w = StdRandom.uniform(v + 1, count);
Edge e = new Edge(w, v);
set.add(e);
G.addEdge(node[w], node[v]);
}
for (int v = 0; v < count - 1; v++) // 生成一棵有出根树,根为 node[count-1]
{
int w = StdRandom.uniform(v + 1, count);
Edge e = new Edge(v, w);
set.add(e);
G.addEdge(node[v], node[w]);
}
} for (; G.E() < E;) // 添加剩余边
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if (!set.contains(e) && v != w && label[v] <= label[w]) // 限制顶点的索引范围,防止出现环
{
set.add(e);
G.addEdge(v, w);
}
}
return G;
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]); StdOut.println("simple");
StdOut.println(simple(V, E)); StdOut.println("Erdos-Renyi");
double p = (double)E / (V*(V - 1) / 2.0);
StdOut.println(simple(V, p)); StdOut.println("complete graph");
StdOut.println(complete(V)); StdOut.println("DAG");
StdOut.println(dag(V, E)); StdOut.println("tournament");
StdOut.println(tournament(V)); StdOut.println("rooted-in DAG");
StdOut.println(rootedInDAG(V, E)); StdOut.println("rooted-out DAG");
StdOut.println(rootedOutDAG(V, E)); StdOut.println("rooted-in tree");
StdOut.println(rootedInTree(V)); StdOut.println("rooted-out DAG");
StdOut.println(rootedOutTree(V)); StdOut.println("path");
StdOut.println(path(V)); StdOut.println("binary tree");
StdOut.println(binaryTree(V)); StdOut.println("cycle");
StdOut.println(cycle(V)); StdOut.println("eulierian cycle");
StdOut.println(eulerianCycle(V, E)); StdOut.println("eulierian path");
StdOut.println(eulerianPath(V, E)); StdOut.println("strong");
StdOut.println(strong(V, E, 4));
}
}

《算法》第四章部分程序 part 3的更多相关文章

  1. 《算法》第四章部分程序 part 19

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径 ● 有边权有向图的邻接矩阵 package p ...

  2. 《算法》第四章部分程序 part 18

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法 ● 在有权有向图中寻找环 package package01; impo ...

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

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,Dijkstra 算法求有向 / 无向图最短路径,以及所有顶点对之间的最短路径 ● Dijkstra 算法求有向图最短路径 package packa ...

  4. 《算法》第四章部分程序 part 15

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树 ● Kruskal 算法求最小生成树 package package01; import e ...

  5. 《算法》第四章部分程序 part 14

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,两种 Prim 算法求最小生成树 ● 简单 Prim 算法求最小生成树 package package01; import edu.princeton ...

  6. 《算法》第四章部分程序 part 10

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,包括无向图连通分量,Kosaraju - Sharir 算法.Tarjan 算法.Gabow 算法计算有向图的强连通分量 ● 无向图连通分量 pack ...

  7. 《算法》第四章部分程序 part 9

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,两种拓扑排序的方法 ● 拓扑排序 1 package package01; import edu.princeton.cs.algs4.Digraph ...

  8. 《算法》第四章部分程序 part 17

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,无环图最短 / 最长路径通用程序,关键路径方法(critical path method)解决任务调度问题 ● 无环图最短 / 最长路径通用程序 pa ...

  9. 《算法》第四章部分程序 part 13

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,图的前序.后序和逆后续遍历,以及传递闭包 ● 图的前序.后序和逆后续遍历 package package01; import edu.princeto ...

  10. 《算法》第四章部分程序 part 12

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,图的几种补充数据结构,包括无向 / 有向符号图,有权边结构,有边权有向图 ● 无向符号图 package package01; import edu. ...

随机推荐

  1. C/C++基础--面向对象编程OOP

    基类通常定义一个虚析构函数,通过基类指针析构派生类对象时不会出现未定义的行为. 如果一个类定义析构函数,编译器不会为这个类合成移动操作. 虚函数覆盖,可以显式地加override,可以让程序员的意图更 ...

  2. this、apply/call、bind、闭包、函数、变量复制

    一.实际场景中抽象出的一个问题 下面this各指向什么? var a = { b: function() { console.log(this); }, f: function() { var c = ...

  3. apk重签名方法

    转载(http://www.51testing.com/?uid-115892-action-viewspace-itemid-223023) 1.      生成Android APK包签名证书 1 ...

  4. Java学习——加法器

    package cys; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.aw ...

  5. python基础介绍

    一. 1.计算机基础 cpu:运算和控制:速度:飞机 内存:临时存储,供给cup数据,断电数据清空.成本高,速度:高铁 硬盘:相当于电脑的数据库,存储大量数据,数据永久保存(除非物理结构被破坏).速度 ...

  6. Java zxing生成二维码所需的jar包

    免费的,不需要积分. 共有2个jar包, 链接: https://pan.baidu.com/s/1QJcEkRQOp1NdrNAgGC6LvQ 密码: 4524

  7. [UE4]修改射击方向

  8. Webpack打包方式及各场景下模块化语法总结

    1.nodejs的方式:commonjs  var xx =require()   modules.exports=xxxx 注意:这种方式引入模块,路径会遵循node的规则,和js的src路径规则不 ...

  9. 2017湖湘杯复赛writeup

    2017湖湘杯复赛writeup 队伍名:China H.L.B 队伍同时在打 X-NUCA  和 湖湘杯的比赛,再加上周末周末周末啊,陪女朋友逛街吃饭看电影啊.所以精力有点分散,做出来部分题目,现在 ...

  10. Vue Admin 后台管理

    https://segmentfault.com/a/1190000009188689