《算法》第四章部分程序 part 18
▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法
● 在有权有向图中寻找环
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.Stack; public class class01
{
private boolean[] marked;
private DirectedEdge[] edgeTo;
private boolean[] onStack; // 各顶点当前是否在搜索栈中,递归回退时要清空
private Stack<DirectedEdge> cycle; // 存储环,若空则表示图中不存在环 public class01(EdgeWeightedDigraph G)
{
marked = new boolean[G.V()];
edgeTo = new DirectedEdge[G.V()];
onStack = new boolean[G.V()];
for (int v = 0; v < G.V(); v++)
{
if (!marked[v])
dfs(G, v);
}
} private void dfs(EdgeWeightedDigraph G, int v)
{
marked[v] = true;
onStack[v] = true;
for (DirectedEdge e : G.adj(v))
{
int w = e.to();
if (cycle != null) // 已经有环了
return;
if (!marked[w])
{
edgeTo[w] = e;
dfs(G, w);
}
else if (onStack[w]) // 该点已经遍历过,且在栈中,即有环
{
cycle = new Stack<DirectedEdge>();
DirectedEdge f = e;
for (; f.from() != w; f = edgeTo[f.from()]) // 回退搜索栈压入 cycle 中,直到该环在搜索栈中的首元素 w 处
cycle.push(f);
cycle.push(f); // 压入环在搜索栈中的首元素 w
return;
}
}
onStack[v] = false; // 递归回退时栈要清空,但 marked 不清空
} public boolean hasCycle()
{
return cycle != null;
} public Iterable<DirectedEdge> cycle()
{
return cycle;
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]); // 新建有边权有向图 G(E,V),再添加 F 条边
int E = Integer.parseInt(args[1]);
int F = Integer.parseInt(args[2]);
EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
for (int i = 0; i < E; i++)
{
int v = 1, w = 0;
for (; v >= w; v = StdRandom.uniform(V), w = StdRandom.uniform(V));
double weight = StdRandom.uniform();
G.addEdge(new DirectedEdge(v, w, weight));
}
for (int i = 0; i < F; i++)
{
int v = StdRandom.uniform(V), w = StdRandom.uniform(V);
double weight = StdRandom.uniform(0.0, 1.0);
G.addEdge(new DirectedEdge(v, w, weight));
} StdOut.println(G); // 原图
class01 finder = new class01(G); // 搜索环
if (finder.hasCycle())
{
StdOut.print("Cycle: ");
for (DirectedEdge e : finder.cycle())
StdOut.print(e + " ");
StdOut.println();
}
else
StdOut.println("No directed cycle");
}
}
● Bellman - Ford 算法求最短路径
package package01; import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
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.Queue; public class class01
{
private double[] distTo; // 起点到各顶点的距离
private DirectedEdge[] edgeTo; // 起点到各顶点的最后一条边
private boolean[] onQueue; // 各顶点当前是否在搜索队中
private Queue<Integer> queue; // 搜索队列
private int cost; // 调用函数 relax 的次数
private Iterable<DirectedEdge> cycle; // 存储负环,若空则表示图中不存在负环 public class01(EdgeWeightedDigraph G, int s)
{
distTo = new double[G.V()];
edgeTo = new DirectedEdge[G.V()];
onQueue = new boolean[G.V()];
for (int v = 0; v < G.V(); v++)
distTo[v] = Double.POSITIVE_INFINITY;
distTo[s] = 0.0;
queue = new Queue<Integer>();
for (queue.enqueue(s), onQueue[s] = true; !queue.isEmpty() && !hasNegativeCycle();) // 存在负环则停止搜索
{
int v = queue.dequeue(); // 每次从搜索队列中拿走一个顶点,松弛以该顶点为起点的边
onQueue[v] = false;
relax(G, v);
}
} private void relax(EdgeWeightedDigraph G, int v)
{
for (DirectedEdge e : G.adj(v))
{
int w = e.to();
if (distTo[w] > distTo[v] + e.weight()) // 加入这条边会使起点到 w 的距离变短
{
distTo[w] = distTo[v] + e.weight();
edgeTo[w] = e;
if (!onQueue[w]) // 注意若 w 已经在搜索队列中则不做任何改变
{
queue.enqueue(w);
onQueue[w] = true;
}
}
if (cost++ % G.V() == 0) // 每当松弛了 V 的倍数次时检查是否存在负环
{
findNegativeCycle();
if (hasNegativeCycle())
return;
}
}
} private void findNegativeCycle() // 利用类 EdgeWeightedDirectedCycle 来找环
{
int V = edgeTo.length;
EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V);
for (int v = 0; v < V; v++)
{
if (edgeTo[v] != null)
spt.addEdge(edgeTo[v]);
}
EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt);
cycle = finder.cycle();
} public boolean hasNegativeCycle()
{
return cycle != null;
} public Iterable<DirectedEdge> negativeCycle()
{
return cycle;
} public boolean hasPathTo(int v)
{
return distTo[v] < Double.POSITIVE_INFINITY;
} public double distTo(int v)
{
if (hasNegativeCycle())
throw new UnsupportedOperationException("\n<distTo> Negative cost cycle exists.\n");
return distTo[v];
} public Iterable<DirectedEdge> pathTo(int v)
{
if (hasNegativeCycle())
throw new UnsupportedOperationException("\n<pathTo> Negative cost cycle exists.\n");
if (!hasPathTo(v))
return null;
Stack<DirectedEdge> path = new Stack<DirectedEdge>();
for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()])
path.push(e);
return path;
} public static void main(String[] args)
{
In in = new In(args[0]);
int s = Integer.parseInt(args[1]);
EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
class01 sp = new class01(G, s);
if (sp.hasNegativeCycle())
{
for (DirectedEdge e : sp.negativeCycle())
StdOut.println(e);
}
else
{
for (int v = 0; v < G.V(); v++)
{
if (sp.hasPathTo(v))
{
StdOut.printf("%d to %d (%5.2f) ", s, v, sp.distTo(v));
for (DirectedEdge e : sp.pathTo(v))
StdOut.print(e + " ");
StdOut.println();
}
else
StdOut.printf("%d to %d no path\n", s, v);
}
}
}
}
● 套汇,本质是寻找负环
package package01; import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.DirectedEdge;
import edu.princeton.cs.algs4.EdgeWeightedDigraph;
import edu.princeton.cs.algs4.BellmanFordSP; public class class01
{
private class01() {} public static void main(String[] args)
{
int V = StdIn.readInt(); // 顶点数
String[] name = new String[V];
EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
for (int v = 0; v < V; v++) // 建图
{
name[v] = StdIn.readString();
for (int w = 0; w < V; w++)
{
double rate = StdIn.readDouble();
DirectedEdge e = new DirectedEdge(v, w, -Math.log(rate));// 汇率取负对数,x1x2x3 < 1 -> -logx1 -logx2 -logx3 < 0
G.addEdge(e);
}
}
BellmanFordSP spt = new BellmanFordSP(G, 0); // 用 BF 算法找负环
if (spt.hasNegativeCycle())
{
double stake = 1000.0;
for (DirectedEdge e : spt.negativeCycle())
{
StdOut.printf("%10.5f %s ", stake, name[e.from()]);
stake *= Math.exp(-e.weight());
StdOut.printf("= %10.5f %s\n", stake, name[e.to()]);
}
}
else
StdOut.println("No arbitrage opportunity");
}
}
《算法》第四章部分程序 part 18的更多相关文章
- 《算法》第四章部分程序 part 19
▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径 ● 有边权有向图的邻接矩阵 package p ...
- 《算法》第四章部分程序 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. ...
随机推荐
- Mysql 性能优化5【重要】数据库结构优化
数据库设计的步骤 我们大多使用mysql 设计三范式 设置时区
- Redis集群事物提交异常Multi-key operations must involve a single slot
redis做完集群后不同键在同一事物中提交,因为key的hash计算结果不同不能分配到同一个分片上,因此出现此异常. 解决方案:在本次事物的key内添加"{tag}",这时redi ...
- Hive 的基本概念
Hadoop开发存在的问题 只能用java语言开发,如果是c语言或其他语言的程序员用Hadoop,存在语言门槛. 需要对Hadoop底层原理,api比较了解才能做开发. Hive概述 Hive是基于H ...
- JSON: 介绍、应用
ylbtech-JSON: 介绍.应用 JSONP(JSON with Padding)是 JSON 的一种“使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据. 为什么我们从不同的 ...
- Eureka与ZooKeeper 的比较(转)
https://www.cnblogs.com/zgghb/p/6515062.html Eureka的优势 1.在Eureka平台中,如果某台服务器宕机,Eureka不会有类似于ZooKeeper的 ...
- netty 3.x 实现http server和遇到的坑
先转载一篇 [初学与研发之NETTY]netty3之文件上传 http://blog.csdn.net/mcpang/article/details/41139859 客户端: [java] view ...
- STM32 f407 温湿度采集报警
软件 keil5 实现 1.使用stm32f407中的DS18B20传感器采集空气温度 2.使用stm32f407中的DHT11传感器采集空气的温度和湿度 3.显示到stm32f407的LCD液晶显示 ...
- Socket传输简单的信息以及粘包问题的解决
一.简单的socket程序——传输简短文字: # -*- coding: utf-8 -*- # -*- Author: WangHW -*- import socket whw_client = s ...
- [UE4]虚幻UE4 .uproject文件无关联 右键菜单少了
前一段时间因为一些事,重装系统 然后重新安装UE4跟VS ,突然发现...竟然之前的UE4原先的项目找不到了,然后用UE4打开就提示 “该文件没有与之关联的程序来执行该操作,请先安装一个程序... ...
- [UE4]一分钟实现聊天系统
天系统:客户端发消息到服务器端,服务器端把收到的消息广播到所有客户端. 由于聊天对象需要支持“可复制”和每个客户端都发给一个,所以GameInstance.GameModeGameState都不适合存 ...