最短路径2----Acyclic算法

通用最短路径算法

distTo[s]初始化0,其余值初始化无穷大,放松G中的任意边,直到不存在有效边为止。此时distTo[w]即为从s到w的最短路径长度,且edgeTo[w]=e表示该最短路径的最后一条边为e。

Dijkstra算法----权重非负的加权有向图最短路径

从通用最短路径算法出发,distTo[s]初始化0,其余值初始化无穷大。不断将distTo[]中最小的非树顶点放松并加入树中,直到所有顶点都在树中,或者所有非树顶点值都为无穷大。

Dijkstra算法每次处理距离起始点距离最近的非树顶点,并且要求加权有向图的边权重非负。下面给出无环加权有向图最短路径一般解法。

无环加权有向图最短路径算法

distTo[s]初始化0,其余值初始化无穷大。按照拓扑排序顺序来放松所有顶点,可以在E+V正比时间内解决无环加权有向图最短路径。

无环加权有向图最短路径问题

顶点拓扑排序问题,利用顶点排序的逆后序。

利用dfs实现顶点排序

//有向图  dfs 顶点排序
//dfs搜索每个顶点会访问一遍   顶点的排序顺序
public class DepthFirstOrder {
	
	private boolean[] marked;
	//dfs过程中  顶点访问顺序
	private Queue<Integer> pre;
	//dfs过程中  某个顶点率先完成所有相邻顶点的访问顺序
	private Queue<Integer> post;
	//dfs过程中  某个顶点率先完成所有相邻顶点的逆序访问顺序
	private Stack<Integer> reversePost;
	
	public DepthFirstOrder(EdgeWeightedDigraph g){
		marked = new boolean[g.V()];
		pre = new LinkedList<>();
		post = new LinkedList<>();
		reversePost = new Stack<>();
		for(int v=0; v<g.V(); v++){
			if(!marked[v]){
				dfs(g, v);
			}	
		}
	}

	private void dfs(EdgeWeightedDigraph g, int v) {
		marked[v] = true;
		//访问该顶点则加入pre队列
		pre.add(v);
		for(DirectedEdge e : g.adj(v)){
			int w = e.to();
			if(!marked[w]){
				dfs(g, w);
			}
		}
		//顶点v所有相邻顶点都访问完毕则加入队列,由于递归其首先访问完成的在队列的最前面,最先输出
		post.add(v);
		//顶点v所有相邻顶点都访问完毕则加入栈  首先完成的在栈最下面,最后输出
		reversePost.push(v);
	}
	
	public Iterable<Integer> pre(){
		return this.pre;
	}
	
	public Iterable<Integer> post(){
		return this.post;
	}
	
	public Iterable<Integer> reversePost(){
		List<Integer> l = new ArrayList<>();
		while(!this.reversePost.isEmpty()){
			l.add(this.reversePost.pop());
		}
		return l;
	}
}

利用顶点排序实现拓扑排序

//拓扑排序  顶点排序逆后序实现方式
public class Topological {
	private Iterable<Integer> order;
	public Topological(EdgeWeightedDigraph g){
		DirectedCycle dc = new DirectedCycle(g);
		if(!dc.hasCycle()){
			DepthFirstOrder dfo = new DepthFirstOrder(g);
			this.order = dfo.reversePost();
		}
	}
	
	public Iterable<Integer> order(){
		return this.order;
	}
	
	public boolean isDAG(){
		return order != null;
	}
}

利用拓扑排序实现无环加权有向图最短路径

//无环加权有向图最短路径算法
public class AcyclicSP {
	
	private DirectedEdge[] edgeTo;
	private double[] distTo;
	
	public AcyclicSP(EdgeWeightedDigraph g, int s){
		edgeTo = new DirectedEdge[g.V()];
		distTo = new double[g.V()];
		for(int v=0; v<g.V(); v++){
			distTo[v] = Double.POSITIVE_INFINITY;
		}
		distTo[s] = 0.0;
		//按照拓扑排序顺序来松弛每个顶点可以得到最短路径
		Topological tp = new Topological(g);
		for(int v : tp.order()){
			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()){
				distTo[w] = distTo[v]+e.weight();
				edgeTo[w] = e;
			}
		}
	}
	
	public double distTo(int v){
		return distTo[v];
	}
	
	public boolean hasPathTo(int v){
		return distTo[v]<Double.POSITIVE_INFINITY;
	}
	
	public Iterable<DirectedEdge> pathTo(int v){
		if(!hasPathTo(v)) return null;
		Stack<DirectedEdge> s = new Stack<>();
		for(DirectedEdge e=edgeTo[v]; e!=null; e=edgeTo[e.from()]){
			s.push(e);
		}
		List<DirectedEdge> ll = new ArrayList<>();
		while(!s.isEmpty()){
			ll.add(s.pop());
		}
		return ll;
	}

}

优先级限制下的并行任务调度

给定一系列任务,每个任务都需要一定的时间,并且某些任务必须在给定的任务之前完成。假定处理器数量是足够的,可以同时进行多个任务的执行,现给出最佳的任务调度方案。

                                                                                      Job-scheduling problem

通过将并行任务调度问题进行转换,可以变为无环加权有向图的最长路径问题。其转换思想如下:

关键路径算法

对于给定的任务创建一个无环加权有向图,包含起始点s,终点t,每个任务对应两个顶点起始和结束顶点;

对于每个任务,从任务起始点指向任务结束点有向边,权重为任务的执行时间;

对于每个优先级限制v-->w,添加一条由v结束顶点指向w开始顶点权重为0的有向边;

对于每个任务的起始顶点,添加一条由s指向每个任务起始顶点权重为0的有向边;

对于每个任务的结束顶点,添加一条由每个任务结束顶点指向结束顶点t的权重0的有向边;

最佳方案的求解等价于从s到t的最长路径问题。

对于上述任务进行转换,得到如下所示:

                           Job-scheduling problem reduction to longest paths

                           Job-scheduling problem critical path

无环加权有向图最长路径问题

通过改进顶点的松弛操作来实现,初始每个顶点初始为负无穷大,只有当发现新的较长路径时才更新distTo和edgeTo数组。

//无环加权有向图单点最长路径算法
public class AcyclicLP {
	
	private DirectedEdge[] edgeTo;
	private double[] distTo;
	
	public AcyclicLP(EdgeWeightedDigraph g, int s){
		edgeTo = new DirectedEdge[g.V()];
		distTo = new double[g.V()];
		for(int v=0; v<g.V(); v++){
			distTo[v] = Double.NEGATIVE_INFINITY;
		}
		distTo[s] = 0.0;
		
		Topological tp = new Topological(g); 
		for(int v : tp.order()){
			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()){
				distTo[w] = distTo[v]+e.weight();
				edgeTo[w] = e;
			}
		}
	}
	
	public double distTo(int v){
		return distTo[v];
	}
	
	public boolean hasPathTo(int v){
		return distTo[v]<Double.POSITIVE_INFINITY;
	}
	
	public Iterable<DirectedEdge> pathTo(int v){
		if(!hasPathTo(v)) return null;
		Stack<DirectedEdge> s = new Stack<>();
		for(DirectedEdge e=edgeTo[v]; e!=null; e=edgeTo[e.from()]){
			s.push(e);
		}
		List<DirectedEdge> ll = new ArrayList<>();
		while(!s.isEmpty()){
			ll.add(s.pop());
		}
		return ll;
	}

}

优先级限制下并行任务调度关键路径算法

//优先级限制下的并行任务调度问题关键路径
public class CPM {
	
	public static void main(String[] args) {
		//任务数量
		int N = 10;
		//每个任务耗时
		double[] ww = new double[]{41,51,50,36,38,45,21,32,32,29};
		//优先级限制  prev[i]要先于next[i]完成
		int[] prev = new int[]{0,0,0,1,6,6,7,7,8,9,9};
		int[] next = new int[]{1,7,9,2,3,8,3,8,2,4,6};
		
		EdgeWeightedDigraph g = new EdgeWeightedDigraph(N*2+2);
		int s = 2*N;
		int t = 2*N+1;
		for(int i=0; i<N; i++){
			//每个任务的起始点和结束点作为一条边
			g.addEdge(new DirectedEdge(i, i+N, ww[i]));
			//起始点s到每个任务的起始点
			g.addEdge(new DirectedEdge(s, i, 0));
			//每个任务的结束点到结束点t
			g.addEdge(new DirectedEdge(i+N, t, 0));
		}
		//添加优先级限制
		for(int i=0; i<prev.length; i++){
			g.addEdge(new DirectedEdge(prev[i]+N, next[i], 0));
		}
		
		AcyclicLP alp = new AcyclicLP(g, s);
		for(int i=0; i<N; i++){
			System.out.println(alp.distTo(i));
		}
		System.out.println(alp.distTo(t));
	}

}

Dijsktra可以解决权重非负的加权有向图问题;Acyclic可以解决无环加权有向图问题。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
### 回答1: dagre-d3 demo 是一个基于dagre和D3.js的演示程序。 dagre是一个基于图形绘制的JavaScript库,用于可视化有向无环图(DAG)。它提供了一种简单易用的方式来创建和布局复杂的图形结构。 D3.js是一个数据驱动的JavaScript库,用于操作文档对象模型(DOM)。它可以根据数据动态创建图形,使得更容易将数据转化为可视化的图表或图形。 dagre-d3 demo结合了这两个库的功能,展示了如何使用dagre和D3.js创建和布局一个有向无环图。demo演示了如何使用dagre-d3来生成图形,并使用D3.js的交互特性来增强图形的可视化效果。 在demo中,你可以看到一个由节点和边组成的图形。每个节点表示一个实体,每条边表示两个实体之间的关联关系。通过拖拽节点和边,你可以对图形进行交互操作。你还可以缩放和平移整个图形,以便更好地查看和分析。 dagre-d3 demo展示了如何使用dagre和D3.js创建复杂的图形,并通过交互式的操作使其更加易于使用和理解。无论是用于学术研究、数据分析还是可视化报告,dagre-d3 demo都是一个非常有用的工具。 ### 回答2: dagre-d3 demo 是一个使用 dagre-d3 库的演示示例。dagre-d3 是一个基于 d3.js 的 JavaScript 库,用于创建和渲染图形。 在这个 demo 中,我们可以看到一个图形,这个图形由多个节点和边组成。每个节点代表一个实体,而边则代表实体之间的关系。 dagre-d3 提供了一些功能,使得我们可以灵活地定义图形的布局和样式。我们可以自定义节点和边的样式,并且可以根据需要修改节点的大小和位置。 在这个 demo 中,我们可以看到节点具有不同的形状和颜色。我们还可以通过鼠标交互来移动和缩放整个图形,以及选择某个节点来查看更详细的信息。 通过使用 dagre-d3 库,我们可以轻松地创建和展示复杂的图形,以及对其进行交互操作。这对于可视化数据、网络拓扑等方面非常有用。 总的来说,dagre-d3 demo 是一个展示 dagre-d3 库功能的示例,通过使用该库的功能,我们可以创建和展示复杂的图形,并且可以通过交互操作对其进行进一步的探索和分析。 ### 回答3: dagre-d3 demo是一个基于dagre和d3库开发的示例项目。dagre是一个在Web浏览器中布局有向无环图(Directed Acyclic Graph, DAG)的JavaScript库,而d3是一个用于数据可视化的JavaScript库。 dagre-d3 demo提供了一个完整而实用的示例,展示了如何使用dagre和d3来布局和展示有向无环图。该示例项目包含了一些预定义的图例和数据,你可以通过点击不同的按钮或链接来切换不同的图例和数据展示。 在dagre-d3 demo中,你可以看到节点(又称为顶点)以及它们之间的连接(边)的可视化呈现。每个节点都有一个唯一的标识符和一些自定义的属性,比如颜色、大小和标签。你可以在示例中通过鼠标悬停在节点上来查看节点的详细信息。 dagre-d3 demo还提供了交互功能,比如拖拽节点来改变它们的位置,点击节点来展开或折叠它们的连接等。这些交互功能增强了用户对图表的探索和理解。 总的来说,dagre-d3 demo是一个展示dagre和d3库强大功能的示例项目,通过使用这两个库,你可以轻松地布局和可视化有向无环图,并且通过交互功能增强了用户体验。这个示例项目可以帮助你更好地理解和应用dagre和d3库来处理和展示图数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值