《算法》第四章部分程序 part 19
▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径
● 有边权有向图的邻接矩阵
package package01; import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.DirectedEdge; public class class01
{
private static final String NEWLINE = System.getProperty("line.separator"); private final int V;
private int E;
private DirectedEdge[][] adj; public class01(int inputV)
{
if (inputV < 0)
throw new IllegalArgumentException("\n<Constructor> V < 0.\n");
V = inputV;
E = 0;
adj = new DirectedEdge[V][V];
} public class01(int inputV, int inputE)
{
this(inputV);
if (inputE < 0 || inputE > V*V)
throw new IllegalArgumentException("\n<Constructor> E < 0 || E > V*V.\n"); for (E = 0; E != inputE;)
{
int v = StdRandom.uniform(V), w = StdRandom.uniform(V);
double weight = Math.round(100 * StdRandom.uniform()) / 100.0;
addEdge(new DirectedEdge(v, w, weight));
}
} public int V()
{
return V;
} public int E()
{
return E;
} public void addEdge(DirectedEdge e)
{
int v = e.from();
int w = e.to();
if (adj[v][w] == null)
{
E++;
adj[v][w] = e;
}
} public Iterable<DirectedEdge> adj(int v)
{
return new AdjIterator(v);
} private class AdjIterator implements Iterator<DirectedEdge>, Iterable<DirectedEdge>
{
private int v;
private int w = 0; public AdjIterator(int inputV)
{
v = inputV;
} public Iterator<DirectedEdge> iterator()
{
return this;
} public boolean hasNext() // 同一行里还有元素(还有以该顶点为起点的边)
{
for (; w < V; w++)
{
if (adj[v][w] != null)
return true; }
return false;
} public DirectedEdge next()
{
if (!hasNext())
throw new NoSuchElementException();
return adj[v][w++];
} public void remove()
{
throw new UnsupportedOperationException();
}
} public String toString()
{
StringBuilder s = new StringBuilder();
s.append(V + " " + E + NEWLINE);
for (int v = 0; v < V; v++)
{
s.append(v + ": ");
for (DirectedEdge e : adj(v))
s.append(e + " ");
s.append(NEWLINE);
}
return s.toString();
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]);
class01 G = new class01(V, E);
StdOut.println(G);
}
}
● FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径
package package01; import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.DirectedEdge;
import edu.princeton.cs.algs4.EdgeWeightedDigraph;
import edu.princeton.cs.algs4.EdgeWeightedDirectedCycle;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.AdjMatrixEdgeWeightedDigraph; public class class01
{
private boolean hasNegativeCycle; // 是否有负环
private double[][] distTo; // 从 v 到 w 的最短路径记作 distTo[v][w]
private DirectedEdge[][] edgeTo; // 从 v 到 w 的最短路径的最后一条边记作 edgeTo[v][w] public class01(AdjMatrixEdgeWeightedDigraph G)
{
int V = G.V();
distTo = new double[V][V];
edgeTo = new DirectedEdge[V][V];
for (int v = 0; v < V; v++) // 邻接表元素初始化为正无穷
{
for (int w = 0; w < V; w++)
distTo[v][w] = Double.POSITIVE_INFINITY;
}
for (int v = 0; v < G.V(); v++)
{
for (DirectedEdge e : G.adj(v)) // 添加以 v 为起点的各条边
{
distTo[e.from()][e.to()] = e.weight();
edgeTo[e.from()][e.to()] = e;
}
if (distTo[v][v] >= 0.0) // 自环归零
{
distTo[v][v] = 0.0;
edgeTo[v][v] = null;
}
}
for (int i = 0; i < V; i++) // 循环 V 次
{
for (int v = 0; v < V; v++) // 用 0 ~ i 作为中间顶点,尝试将其引入
{
if (edgeTo[v][i] == null) // v 不可达 i,跳过
continue;
for (int w = 0; w < V; w++)
{
if (distTo[v][w] > distTo[v][i] + distTo[i][w]) // 引入顶点 i 使得 v 到 w 的距离缩短
{
distTo[v][w] = distTo[v][i] + distTo[i][w]; // 正式引入顶点 i
edgeTo[v][w] = edgeTo[i][w];
}
}
if (distTo[v][v] < 0.0) // 检测负环,条件是某顶点到自身的最短路径小于 0
{
hasNegativeCycle = true;
return;
}
}
}
} public boolean hasNegativeCycle()
{
return hasNegativeCycle;
} public Iterable<DirectedEdge> negativeCycle()
{
for (int v = 0; v < distTo.length; v++)
{
if (distTo[v][v] < 0.0)
{
int V = edgeTo.length;
EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V);
for (int w = 0; w < V; w++) // 把与 v 有关的边加入一个含边权有向图,用类 EdgeWeightedDirectedCycle 寻找环
{
if (edgeTo[v][w] != null) // 实际上所有从 v 延伸出去的最短路径的边都加上了
spt.addEdge(edgeTo[v][w]);
}
EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt);
return finder.cycle();
}
}
return null;
} public boolean hasPath(int s, int t)
{ return distTo[s][t] < Double.POSITIVE_INFINITY;
} public double dist(int s, int t)
{
if (hasNegativeCycle())
throw new UnsupportedOperationException("\n<dist> Negative cost cycle exists.\n");
return distTo[s][t];
} public Iterable<DirectedEdge> path(int s, int t)
{
if (hasNegativeCycle())
throw new UnsupportedOperationException("\n<Iterable> Negative cost cycle exists.\n");
if (!hasPath(s, t))
return null;
Stack<DirectedEdge> path = new Stack<DirectedEdge>();
for (DirectedEdge e = edgeTo[s][t]; e != null; e = edgeTo[s][e.from()])
path.push(e);
return path;
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]);
AdjMatrixEdgeWeightedDigraph G = new AdjMatrixEdgeWeightedDigraph(V);
for (int i = 0; i < E; i++)
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
double weight = Math.round(100 * (StdRandom.uniform() - 0.15)) / 100.0;
if (v == w) G.addEdge(new DirectedEdge(v, w, Math.abs(weight)));
else G.addEdge(new DirectedEdge(v, w, weight));
} StdOut.println(G);
class01 spt = new class01(G);
StdOut.printf(" ");
for (int v = 0; v < G.V(); v++)
StdOut.printf("%6d ", v);
StdOut.println();
for (int v = 0; v < G.V(); v++)
{
StdOut.printf("%3d: ", v);
for (int w = 0; w < G.V(); w++)
{
if (spt.hasPath(v, w))
StdOut.printf("%6.2f ", spt.dist(v, w));
else
StdOut.printf(" Inf "); // 存在负环的路径长度显示为负无穷
}
StdOut.println();
}
if (spt.hasNegativeCycle()) // 有负环单独显示,否则正常显示各条最短路径
{
StdOut.println("Negative cost cycle:");
for (DirectedEdge e : spt.negativeCycle())
StdOut.println(e);
StdOut.println();
}
else
{
for (int v = 0; v < G.V(); v++)
{
for (int w = 0; w < G.V(); w++)
{
if (spt.hasPath(v, w)) {
StdOut.printf("%d to %d (%5.2f) ", v, w, spt.dist(v, w));
for (DirectedEdge e : spt.path(v, w))
StdOut.print(e + " ");
StdOut.println();
}
else
StdOut.printf("%d to %d no path\n", v, w);
}
}
}
}
}
《算法》第四章部分程序 part 19的更多相关文章
- 《算法》第四章部分程序 part 18
▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法 ● 在有权有向图中寻找环 package package01; impo ...
- 《算法》第四章部分程序 part 16
▶ 书中第四章部分程序,包括在加上自己补充的代码,Dijkstra 算法求有向 / 无向图最短路径,以及所有顶点对之间的最短路径 ● Dijkstra 算法求有向图最短路径 package packa ...
- 《算法》第四章部分程序 part 15
▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树 ● Kruskal 算法求最小生成树 package package01; import e ...
- 《算法》第四章部分程序 part 14
▶ 书中第四章部分程序,包括在加上自己补充的代码,两种 Prim 算法求最小生成树 ● 简单 Prim 算法求最小生成树 package package01; import edu.princeton ...
- 《算法》第四章部分程序 part 10
▶ 书中第四章部分程序,包括在加上自己补充的代码,包括无向图连通分量,Kosaraju - Sharir 算法.Tarjan 算法.Gabow 算法计算有向图的强连通分量 ● 无向图连通分量 pack ...
- 《算法》第四章部分程序 part 9
▶ 书中第四章部分程序,包括在加上自己补充的代码,两种拓扑排序的方法 ● 拓扑排序 1 package package01; import edu.princeton.cs.algs4.Digraph ...
- 《算法》第四章部分程序 part 17
▶ 书中第四章部分程序,包括在加上自己补充的代码,无环图最短 / 最长路径通用程序,关键路径方法(critical path method)解决任务调度问题 ● 无环图最短 / 最长路径通用程序 pa ...
- 《算法》第四章部分程序 part 13
▶ 书中第四章部分程序,包括在加上自己补充的代码,图的前序.后序和逆后续遍历,以及传递闭包 ● 图的前序.后序和逆后续遍历 package package01; import edu.princeto ...
- 《算法》第四章部分程序 part 12
▶ 书中第四章部分程序,包括在加上自己补充的代码,图的几种补充数据结构,包括无向 / 有向符号图,有权边结构,有边权有向图 ● 无向符号图 package package01; import edu. ...
随机推荐
- Delphi XE5开发Android程序使用自定义字体文件.
万事大吉,只欠根据字体文件(.ttf文件)切换阅读字体,通常Android系统只带三种以下字体.一般用Java/Eclipse开发的话比较简单,typeface的createFromAsset,cre ...
- Docker-compose ports和expose的区别
docker-compose中有两种方式可以暴露容器的端口:ports和expose. 1 ports ports暴露容器端口到主机的任意端口或指定端口,用法: ports: - "80:8 ...
- Mysql 性能优化6【重要】 索引优化
b tree索引 myisam 是通过物理位置来查找引用行的 innodb 是通过主键来查找引用行的 索引优化策略 b-tree索引对数据长度有限制,所以text等比较长的列可以建立前缀索引 btre ...
- Python开发工具Atom
python基础教程之Python开发工具Atom 本节内容如下: Atom简介 下载安装Atom 安装Python开发包 使用Atom开发Python程序 Atom简介 Atom是Github开 ...
- 【Graphite】Graphite常用函数使用
使用Graphite进行sort排名 限制返回条数 aliasByNode(limit(sortByMaxima(summarize(EPIC.bm.00*.memory.memory.buffere ...
- MongoDB查询结果存放入新的Collection
第一种方法 var lst = db.visits_201501.find({ "url":/http:\/\/m.baidu.com\/application/ }); whil ...
- .NET使用Task动态创建多任务多线程并行程序计算Redis集群keys计算
Task是一个很好用的多任务处理类,并且通过Task可以对任务进行很好的控制. 下面将通过代码实现Redis集群在使用IServer.keys时通过多任务对多个服务器示例进行并行计算,并对返回key做 ...
- css中背景的应用
浏览器默认的字体大小是 font-size:16px; 谷歌最小的是10px 其他浏览器是12px 通配符选择器 * “*”的意思是代表所有的标签 回到正题 background 背景 他的几 ...
- centos 7扩展磁盘分区容量
一.fdisk -l 查看磁盘空间大小 二. 1.fdisk /dev/sda 增加分区 2.判断应增加的分区号 键入n,增加一个分区 3.键入p,主分区,并键入(编号) 4.起始扇区和结束扇区(默认 ...
- Jmeter(七)Jmeter脚本优化(数据与脚本分离)
午休时间再来记一记,嗯..回顾着使用Jmeter的历程,想着日常都会用到的一些功能.一些组件:敲定了本篇的主题----------是的.脚本优化. 说起脚本优化,为什么要优化?又怎么优化?是个永恒的话 ...