有向图之任务调度拓扑图介绍
1.有向图的数据类型
使用Bag表示有向图,其中边v->w表示为顶点v所对应的邻接链表中包含一个w顶点,与无向图不同的是,这里每条边只会出现一次.有向图的数据结构类型如下:
public class Digraph {private final int V;private int E;private Bag<Integer>[] adj;public Digraph(int V) {this.V=V;this.E=0; adj=(Bag<Integer>[])new Bag[V];for(int v=0;v<V;v++) { adj[v]=new Bag<Integer>(); } }public int V() {return V; }public int E() {return E; }//添加一条边v->w,由于是有向图只要添加一条边就可以了public void addEdge(int v,int w) { adj[v].add(w); E++; }public Iterable<Integer> adj(int v) {return adj[v]; }//返回当前图的一个反向的图public Digraph reverse() { Digraph R=new Digraph(V);for(int v=0;v<V;v++) {for(int w:adj(v)) { R.addEdge(w, v); } }return R; } }
2.有向图中的可达性
无向图的连通性相似,同利用深度优先搜索可以解决有向图中
单点可达性问题:即:给定一幅有向图和一个起点s,回答是否存在一条从s到达给定顶点v的有向路径的问题.
多点可达性问题:给定一幅有向图和顶点的集合,回答是否存在一条从集合中的任意顶点到达给定顶点v的有向路径?
public class DirectedDFS {private boolean[] marked;//从G中找出所有s可达的点public DirectedDFS(Digraph G,int s) { marked=new boolean[G.V()]; dfs(G,s); }//G中找出一系列点可达的点public DirectedDFS(Digraph G,Iterable<Integer> sources) { marked=new boolean[G.V()];for(int s:sources) {if(!marked[s]) dfs(G,s); } }//深度优先搜素判断.private void dfs(Digraph G, int v) { marked[v]=true;for(int w:G.adj(v)) {if(!marked[w]) dfs(G,w); } }//v是可达的吗public boolean marked(int v) {return marked[v]; } }
多点可达性问题的一个重要时机应用是在典型的内存管理系统中,包括许多java的实现。在一个有向图中,一个顶点表示一个对象,一条边则表示一个对象对另一个对象的引用。
这个模型很好表现了运行中的java程序的内存使用状况。在程序执行的任何时候都有某些对象是可以被直接访问的,而不能通过这些对象访问到的所有对象都应该被回收以便
释放内存。它会周期性的运行一个类似于DirectedDFS的有向图可达性算法来标记所有可以被访问到的对象。
3.有向图的寻路
和无向图类似,有向图中常见的问题:
单点有向路径。给定一幅有向图和一个起点,回答“从s到给定目的顶点v是否存在一条有向路径?如果有,找出这条路径”
单点最短有向路径。给定一幅有向图和一个起点,回答“从s到给定目的顶点v是否存在一条有向路径,如果有,找出其中最短的那条(所含边数最少)”
4.调度问题—拓扑排序
4.1寻找有向环
如果一个有优先限制的问题中存在有向环,那么这个问题肯定是无解的。所以需要进行有向环的检测。
下面的代码可以用来检测给定的有向图中是否含有有向环,如果有,则按照路径的方向返回环上的所有顶点.
在执行dfs的时候,查找的是从起点到v的有向路径,onStack数组标记了递归调用的栈上的所有顶点,同时也加入了edgeTo数组,在找到有向环的时候返回环中的所有顶点.
/** * 有向图G是否含有有向环 * 获取有向环中的所有顶点 * @author Administrator * */public class DirectedCycle {private boolean[] marked; private int[] edgeTo;private Stack<Integer> cycle; //有向环中的所有顶点private boolean[] onStack; //递归调用的栈上的所有顶点public DirectedCycle(Digraph G) { edgeTo=new int[G.V()]; onStack=new boolean[G.V()]; marked=new boolean[G.V()];for(int v=0;v<G.V();v++) {if(!marked[v]) dfs(G,v); } }/** * 该算法的关键步骤在于onStack数组的运用. * onStack数组标记的是当前遍历的点.如果对于一个点指向的所有点中的某个点 * onstack[v]=true.代表该点正在被遍历也就是说 * 该点存在一条路径,指向这个点.而这个点现在又可以指向该点, * 即存在环的结构~ * @param G * @param v */ private void dfs(Digraph G, int v) { onStack[v]=true; marked[v]=true;for(int w:G.adj(v)) {if(this.hasCycle()) return;else if(!marked[w]) { edgeTo[w]=v; dfs(G,w); }else if(onStack[w]) { cycle=new Stack<Integer>();for(int x=v;x!=w;x=edgeTo[x]) cycle.push(x); cycle.push(w); cycle.push(v); } }//dfs方法结束,对于该点的递归调用结束.该点指向的所有点已经遍历完毕onStack[v]=false; }private boolean hasCycle() {return cycle!=null; }public Iterable<Integer> cycle() {return cycle; } }
4.2 拓扑排序
拓补排序:给定一幅有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素.如果存在有向环的话,那么拓补排序无法完成.
要实现有向图的拓补排序,利用标准深度优先搜索顺序即可完成任务.这里顶点会有三种排列顺序:
1.前序:在递归调用前将顶点加入队列
2.后序:在递归调用之后将顶点加入队列
3.逆后序:在递归调用之后将顶点压入栈.
具体的操作见下面的代码:
//有向图中基于深度优先搜索的拓补排序public class DepthFirstOrder {private boolean[] marked;private Queue<Integer> pre; //所有顶点的前序排列private Queue<Integer> post; //所有顶点的后序排列private Stack<Integer> reversePost;//所有顶点的逆后序排列public DepthFirstOrder(Digraph G) { pre=new Queue<>(); post=new Queue<>(); reversePost=new Stack<>(); marked=new boolean[G.V()]; for(int v=0;v<G.V();v++) {if(!marked[v]) dfs(G,v); } }private void dfs(Digraph G, int v) { pre.enqueue(v);marked[v]=true;for(int w:G.adj(v)) {if(!marked[w]) { dfs(G,w); } } post.enqueue(v); reversePost.push(v);}public Iterable<Integer> pre() {return pre; }public Iterable<Integer> post() {return post; }public Iterable<Integer> reversePost() {return reversePost; } }
遍历的顺序取决于这个数据结构的性质以及是在递归调用之前还是之后进行保存。
前序:在递归调用之前将顶点加入队列。
后序:在递归调用之后将顶点加入队列。
逆后序:在递归调用之后将顶点压入栈。
前序就时dfs()的调用顺序;后序就是顶点遍历完成的顺序;逆后序就是顶点遍历完成顺序的逆。
拓补排序的实现依赖于上面的API,实际上拓补排序即为所有顶点的逆后序排列
拓补排序的代码如下:
public class Topological {private Iterable<Integer> order; //顶点的拓补排序public Topological(Digraph G) { DirectedCycle cyclefinder=new DirectedCycle(G);if(!cyclefinder.hasCycle()) {//只有无环才能进行拓补排序DepthFirstOrder dfs=new DepthFirstOrder(G); order=dfs.reversePost(); } }public Iterable<Integer> order() {return order; }public boolean isDAG() {return order!=null; } }
5.有向图的强连通性
定义:如果两个顶点v和w是互相可达的,则称它们为强连通的.也就是说既存在一条从v到w的有向路径也存在一条从w到v的有向路径.
如果一幅有向图中的任意两个顶点都是强连通的,则称这副有向图也是强连通的.任意顶点和自己都是强连通的.
下面的代码采用如下步骤来计算强连通分量以及两个点是否是强连通的:
1.在给定的有向图中,使用DepthFirsetOrder来计算它的反向图GR的逆后序排列
2.按照第一步计算得到的顺序采用深度优先搜索来访问所有未被标记的点
3.在构造函数中,所有在同一个递归dfs()调用中被访问到的顶点都是在同一个强连通分量中.
下面的代码实现遵循了上面的思路:
/** * 该算法实现的关键: * 使用深度优先搜索查找给定有向图的反向图GR.根据由此得到的所有顶点的逆后序 * 再次用深度优先搜索处理有向图G.其构造函数的每一次递归调用所标记的顶点都在 * 同一个强连通分量中. * 解决问题: * 判断两个点是否是强连通的 * 判断总共有多少个连通分量 * @author Administrator * */public class KosarajuSCC {private boolean[] marked;//已经访问过的顶点private int[] id; //强连通分量的标识符private int count; //强联通分量的数量public KosarajuSCC(Digraph G) { marked=new boolean[G.V()]; id=new int[G.V()]; DepthFirstOrder order=new DepthFirstOrder(G.reverse());for(int s:order.reversePost()) {if(!marked[s]) { dfs(G,s); count++; } } }private void dfs(Digraph G, int v) { marked[v]=true; id[v]=count;for(int w:G.adj(v)) {if(!marked[w]) { dfs(G,w); } } }public boolean stronglyConnected(int v,int w) {return id[v]==id[w]; }public int id(int v) {return id[v]; }public int count() {return count; } }
以上是有向图之任务调度拓扑图介绍的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

恐怖走廊是模拟山羊3之中的一个任务,这个任务要怎么样才能够去完成呢,掌握到详细的过关方式和对应的流程,能够完成这个任务的相应挑战,下面就为大家带来模拟山羊3恐怖走廊攻略,了解相关的信息。模拟山羊3恐怖走廊攻略1、首先需要玩家前往地图左上角的寂静岭处。2、在这里可以看到一个屋顶上写着RESTSTOP的房子,玩家需要操作山羊进入这个房子。3、进入房间之后,我们首先向前直走,随后向右转,在这里尽头有一扇门,我们直接从这里进去。4、进入之后同样是先向前走随后右转,在这里走到门前门会关上,我们需要回头找到

要自动化任务和管理多个系统,任务计划软件是您武器库中的宝贵工具,尤其是对于系统管理员而言。Windows任务计划程序完美地完成了这项工作,但最近许多人报告说操作员拒绝了请求错误。该问题存在于操作系统的所有迭代中,即使已经广泛报告和涵盖,也没有有效的解决方案。继续阅读以找到真正对其他人有用的内容!操作员或管理员拒绝了任务计划程序0x800710e0中的请求是什么?任务计划程序允许在没有用户输入的情况下自动执行各种任务和应用程序。您可以使用它来安排和组织特定应用程序、配置自动通知、帮助传递消息等。它

模拟山羊3是有着经典模拟玩法的游戏,可让玩家充分体验到休闲动作类操作模拟的乐趣,游戏中还拥有很多特色任务的精彩,其中模拟山羊3帝陵任务是需要玩家找寻到钟塔上的三个钟并操作的,一些玩家还不清楚要怎么弄,下面带来模拟山羊3帝陵任务攻略流程分享!模拟山羊3帝陵任务攻略流程按照顺序敲击钟即可。详细步骤拓展1、首先玩家需要打开地图去到雾丘公墓。2、然后上到钟楼上,里面会有着三个钟。3、接着按照从大到小的顺序,按照222312312熟悉怒敲击。4、完成敲击后即可完成任务,并打开大门获得光剑。

营救史蒂夫是模拟山羊3中的一个独特任务,具体需要怎么做才能够完成呢,这个任务比较简单,但是我们需要注意不要理解错意思,下面就为大家带来模拟山羊3营救史蒂夫任务攻略,能够更好的完成相关的任务。模拟山羊3营救史蒂夫任务攻略1、首先来到地图中右下角的温泉。2、在来到温泉边上之后就可以触发营救史蒂夫的这个任务。3、注意在温泉里有个男人,虽然他也叫史蒂夫,但是并不是本次任务的目标。4、在这个温泉里找到一条叫史蒂夫的鱼,并且将其带上岸,即可完成这个任务。

抖音作为当下最受欢迎的社交媒体平台之一,吸引了大量用户参与其中。在抖音上,有很多粉丝团任务可供用户完成,从而获得一定的奖励和福利。那么,抖音粉丝团任务在哪里可以找到呢?一、抖音粉丝团任务在哪里看?为了找到抖音粉丝团任务,你需要访问抖音的个人主页。在主页上,你会看到一个名为“粉丝团”的选项。点击这个选项,你就可以浏览你所加入的粉丝团和相关任务。在粉丝团任务栏目中,你会看到各种不同类型的任务,如点赞、评论、分享、转发等。每个任务都有对应的奖励和要求,一般来说,完成任务后会获得一定数量的金币或者经验值

如何在Windows11和Windows10中暂停任务管理器进程更新按CTRL+窗口键+删除打开任务管理器。默认情况下,任务管理器将打开“进程”窗口。正如您在此处看到的,所有应用程序都在无休止地移动,当您想要选择它们时,可能很难将它们指向下方。因此,按CTRL并按住它,这将暂停任务管理器。您仍然可以选择应用程序,甚至可以向下滚动,但您必须始终按住CTRL按钮。

实现任务通用是深度学习基础模型研究的核心问题,也是近期大模型方向的主要关注点之一。然而,在时间序列领域,各类分析任务的差别较大,既有需要细粒度建模的预测任务,也有需要提取高层语义信息的分类任务。如何构建统一的深度基础模型高效地完成各类时序分析任务,此前尚未有成型方案。为此,来自清华大学软件学院的团队围绕时序变化建模这一基本问题展开研究,提出了任务通用的时序基础模型TimesNet,论文被ICLR 2023接收。作者列表:吴海旭*,胡腾戈*,刘雍*,周航,王建民,龙明盛链接:https://ope

冻结或无响应的程序很容易从任务管理器中杀死。但是Microsoft最近为用户提供了直接从任务栏终止这些任务的便利。虽然该选项并未向所有人推出,但如果您有WindowsInsider版本,则很容易获得。以下是启用“结束任务”按钮并从任务栏关闭任务所需的一切。如何从任务栏中获取“结束任务”按钮以杀死应用目前,为任务栏应用启用“结束任务”按钮的选项仅作为具有Windows预览体验成员版本的用户的开发人员选项提供。但是,这在即将推出的功能更新中可能会发生变化,因为它将在稳定版本上向全球用户推出。如果您尚
