小书匠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后,关键路径变化.

最新文章

  1. ElasticSearch 配置详解
  2. Spring MVC学习笔记——POJO和DispatcherServlet
  3. 1 、Linux-Rhel6终端介绍-Shell提示符
  4. CSS3之firefox&safari背景渐变之争 - [前端技术][转]
  5. go lang学习笔记——channel机理及调度理解
  6. IOS公司开发者账号申请详细教程
  7. JQuery向ashx提交中文参数方案
  8. 【JS】Advanced1:Object-Oriented Code
  9. Qt写的截图软件包含源代码和可执行程序
  10. rk3288 ov8858 camera移植
  11. mysql 查看mysql版本的四种方法
  12. JS - 循环添加 DropDownList(Select)
  13. 经常使用git命令集
  14. 用Chrome开发者工具做JavaScript性能分析
  15. zepto学习之路--数组去重和原生reduce
  16. [翻译]QT core wallet manual 狗狗币核心钱包使用教程
  17. 2019/4/22 kmp模板
  18. HttpServerUtility常用方法
  19. 高可用Hadoop平台-运行MapReduce程序
  20. Shell脚本开发规范

热门文章

  1. 在论坛中出现的比较难的sql问题:28(循环查询表来实现递归)
  2. LunHui 的生命观
  3. Go net/http,web server
  4. 数据结构之链表(LinkedList)(一)
  5. Tomcat安装及环境配置
  6. 支付宝APP支付(基于Java实现支付宝APP支付)
  7. 孤陋寡闻了吧?Python 居然可以做这30件神奇好玩的事情(附教程)
  8. C++(三十四) — 友元函数、友元类
  9. osi七层网络模型(一)
  10. Windows 对外开放端口号