小书匠Graph图论

重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图论中常用算法弄个明白在写这部分.

图论常用算法看我的博客:

下面我将使用NetworkX实现上面的算法,建议不清楚的部分打开两篇博客对照理解.

我将图论的经典问题及常用算法的总结写在下面两篇博客中:

图论---问题篇

图论---算法篇

目录:

* 11.3关键路径算法(CPA)


注意:如果代码出现找不库,请返回第一个教程,把库文件导入.

11.3关键路径算法(CPA)

以下代码从这里复制,由于版本问题,将代码中的:nx.topological_sort(self, reverse=True)改为list(reversed(list(nx.topological_sort(self))))

  1. import networkx as nx 

  2. import matplotlib.pyplot as plt 

  3. from matplotlib.font_manager import *  


  4. #定义自定义字体,文件名从1.b查看系统中文字体中来  

  5. myfont = FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc')  

  6. #解决负号'-'显示为方块的问题  

  7. matplotlib.rcParams['axes.unicode_minus']=False  


  8. class CPM(nx.DiGraph): 


  9. def __init__(self): 

  10. super().__init__() 

  11. self._dirty = True 

  12. self._critical_path_length = -1 

  13. self._criticalPath = None 


  14. def add_node(self, *args, **kwargs): 

  15. self._dirty = True 

  16. super().add_node(*args, **kwargs) 


  17. def add_nodes_from(self, *args, **kwargs): 

  18. self._dirty = True 

  19. super().add_nodes_from(*args, **kwargs) 


  20. def add_edge(self, *args): # , **kwargs): 

  21. self._dirty = True 

  22. super().add_edge(*args) # , **kwargs) 


  23. def add_edges_from(self, *args, **kwargs): 

  24. self._dirty = True 

  25. super().add_edges_from(*args, **kwargs) 


  26. def remove_node(self, *args, **kwargs): 

  27. self._dirty = True 

  28. super().remove_node(*args, **kwargs) 


  29. def remove_nodes_from(self, *args, **kwargs): 

  30. self._dirty = True 

  31. super().remove_nodes_from(*args, **kwargs) 


  32. def remove_edge(self, *args): # , **kwargs): 

  33. self._dirty = True 

  34. super().remove_edge(*args) # , **kwargs) 


  35. def remove_edges_from(self, *args, **kwargs): 

  36. self._dirty = True 

  37. super().remove_edges_from(*args, **kwargs) 


  38. #根据前向拓扑排序算弧的最早发生时间 

  39. def _forward(self): 

  40. for n in nx.topological_sort(self): 

  41. es = max([self.node[j]['EF'] for j in self.predecessors(n)], default=0) 

  42. self.add_node(n, ES=es, EF=es + self.node[n]['duration']) 


  43. #根据前向拓扑排序算弧的最迟发生时间 

  44. def _backward(self): 

  45. #for n in nx.topological_sort(self, reverse=True): 

  46. for n in list(reversed(list(nx.topological_sort(self)))): 

  47. lf = min([self.node[j]['LS'] for j in self.successors(n)], default=self._critical_path_length) 

  48. self.add_node(n, LS=lf - self.node[n]['duration'], LF=lf) 


  49. #最早发生时间=最迟发生时间,则判断该节点为关键路径上的关键活动 

  50. def _compute_critical_path(self): 

  51. graph = set() 

  52. for n in self: 

  53. if self.node[n]['EF'] == self.node[n]['LF']: 

  54. graph.add(n) 

  55. self._criticalPath = self.subgraph(graph) 


  56. @property 

  57. def critical_path_length(self): 

  58. if self._dirty: 

  59. self._update() 

  60. return self._critical_path_length 


  61. @property 

  62. def critical_path(self): 

  63. if self._dirty: 

  64. self._update() 

  65. return sorted(self._criticalPath, key=lambda x: self.node[x]['ES']) 


  66. def _update(self): 

  67. self._forward() 

  68. self._critical_path_length = max(nx.get_node_attributes(self, 'EF').values()) 

  69. self._backward() 

  70. self._compute_critical_path() 

  71. self._dirty = False 


  72. if __name__ == "__main__": 


  73. #构建graph 

  74. G = CPM() 

  75. G.add_node('A', duration=5) 

  76. G.add_node('B', duration=2) 

  77. G.add_node('C', duration=4) 

  78. G.add_node('D', duration=4) 

  79. G.add_node('E', duration=3) 

  80. G.add_node('F', duration=7) 

  81. G.add_node('G', duration=4) 


  82. G.add_edges_from([ 

  83. ('A', 'B'), 

  84. ('A', 'C'), 

  85. ('C','D'), 

  86. ('C','E'), 

  87. ('C','G'), 

  88. ('B','D'), 

  89. ('D','F'), 

  90. ('E','F'), 

  91. ('G','F'), 

  92. ])  


  93. #显示graph 

  94. nx.draw_spring(G,with_labels=True) 

  95. plt.title('AOE网络',fontproperties=myfont) 

  96. plt.axis('on') 

  97. plt.xticks([]) 

  98. plt.yticks([]) 

  99. plt.show() 



  100. print('关键活动为:') 

  101. print(G.critical_path_length, G.critical_path) 


  102. G.add_node('D', duration=2) 

  103. print('\n修改D活动持续时间4为2后的关键活动为:') 

  104. print(G.critical_path_length, G.critical_path) 


关键路径示例(该图非黑色线为手工绘制,数字手工添加)

从graph中可以知道,有两条关键路径,分别是:A->C->G->FA->C->D->F,长度都是20.

输出:

关键活动为: 20 ['A', 'C', 'D', 'G', 'F']

修改D活动持续时间4为2后的关键活动为: 20 ['A', 'C', 'G', 'F']

关键活动为: ['A', 'C', 'D', 'G', 'F'],可以构成两条边.D活动持续时间4为2后,关键路径变化.

NetworkX系列教程(10)-算法之三:关键路径问题的更多相关文章

  1. NetworkX系列教程(10)-算法之五:广度优先与深度优先

    小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...

  2. NetworkX系列教程(10)-算法之四:拓扑排序与最大流问题

    小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...

  3. NetworkX系列教程(10)-算法之二:最小/大生成树问题

    小书匠 Graph 图论  重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定 ...

  4. NetworkX系列教程(10)-算法之一:最短路径问题

    小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...

  5. NetworkX系列教程(9)-线性代数相关

    小书匠 Graph 图论  学过线性代数的都了解矩阵,在矩阵上的文章可做的很多,什么特征矩阵,单位矩阵等.grpah存储可以使用矩阵,比如graph的邻接矩阵,权重矩阵等,这节主要是在等到graph后 ...

  6. NetworkX系列教程(2)-graph生成器

    小书匠Graph图论 本节主要讲解如何快速使用内置的方法生成graph,官方的文档在这里,里面包含了networkX的所有graph生成器,下面的内容只是我节选的内容,并将graph画出来而已. 声明 ...

  7. NetworkX系列教程(1)-创建graph

    小书匠Graph图论 研究中经常涉及到图论的相关知识,而且常常面对某些术语时,根本不知道在说什么.前不久接触了NetworkX这个graph处理工具,发现这个工具已经解决绝大部分的图论问题(也许只是我 ...

  8. HTML5游戏开发系列教程10(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-10/ 最后我们将继续使用canvas来进行HTML5游戏开发系列 ...

  9. Python Twisted系列教程10:增强defer功能的客户端

    作者:dave@http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/ 译者:杨晓伟(采用意译) 可以从这 ...

随机推荐

  1. js 自定义加减乘除方法(防止js自身计算错误)

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. 基于NetCore+SqlSugar+Layui开发出来的开源框架项目FytSoaCms问题处理

    最近刚好在学习NetCore框架所以就在网上搜索了一下相关的开源框架项目,正好在Github上找到了一个不错的开源框架所以推荐给大家看看哈哈哈. 1:项目相关技术 运行NetCore SDK版本为2. ...

  3. 多进程,多线程,使用sqlalchemy 创建引擎(单例模式),闭包装饰器承载数据库会话,装饰模型类的类方法

    python 多进程,多线程,使用 sqlalchemy 对数据库进行操作 创建引擎 & 获取数据库会话: 使用类的方式,然后在对象方法中去创建数据库引擎(使用单例,确保只创建一个对象,方法里 ...

  4. [转]全网最!详!细!tarjan算法讲解

    转发地址:https://blog.csdn.net/qq_34374664/article/details/77488976 原版的地址好像挂了..... 看到别人总结的很好,自己就偷个懒吧..以下 ...

  5. jQuery 基础知识

    一.序言 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后的又一个优秀的JavaScript代码库(JavaScript框架).jQuery设计的宗旨是"W ...

  6. 1-JavaScript变量

    对于JS的变量这个环节,其实主要要了解一下JS数据类型的存储方法 JS有两种不同的数据类型:基本类型(原始类型),引用类型(对象类型). 1.栈 (stack) 和 堆 (heap) 栈 (stack ...

  7. S3C2440 OpenJtag

    C:\Users\Administrator\Desktop>oflash.exe leds.bin +--------------------------------------------- ...

  8. 【JUC】2.synchronized

    synchronized关键字的用法也不做太多笔记了,简单回顾一下: synchronized三种使用方式: 修饰实例方法: 线程获取的是当前调用此方法的对象的对象头:即:锁是当前对象: public ...

  9. CSS之属相相关

    一.padding与margin padding:就是内边距的意思,它是边框到内容之间的距离 另外padding的区域是有背景颜色的.并且背景颜色和内容的颜色一样.也就是说background-col ...

  10. Windows Server 2008上网设置——IE

    IE安装设置 在 Windows Sever 2008 中打开 IE 浏览器时,IE 会出现[已启用 Internet Explorer 增强的安全配置]的提示信息. Windows Server 2 ...