1.拓扑排序

一个无环的有向图称为无环图(Directed Acyclic Graph),简称DAG图。 所有的工程或者某种流程都可以分为若干个小的工程或者阶段,我们称这些小的工程或阶段为“活动”。 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称之为AOV网(Active On Vertex Network)。
拓扑序列:设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,……,Vn满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前。则我们称这样的顶点序列为一个拓扑序列。 拓扑排序:所谓的拓扑排序,其实就是对一个有向图构造拓扑序列的过程。

2.关键路径

  1. // 边表结点声明
  2. typedef struct EdgeNode
  3. {
  4. int adjvex;
  5. struct EdgeNode *next;
  6. }EdgeNode;
  7. // 顶点表结点声明
  8. typedef struct VertexNode
  9. {
  10. int in; // 顶点入度
  11. int data;
  12. EdgeNode *firstedge;
  13. }VertexNode, AdjList[MAXVEX];
  14. typedef struct
  15. {
  16. AdjList adjList;
  17. int numVertexes, numEdges;
  18. }graphAdjList, *GraphAdjList;
  19. int *etv, *ltv;
  20. int *stack2; // 用于存储拓扑序列的栈
  21. int top2; // 用于stack2的栈顶指针
  22. // 拓扑排序算法
  23. // 若GL无回路,则输出拓扑排序序列并返回OK,否则返回ERROR
  24. Status TopologicalSort(GraphAdjList GL)
  25. {
  26. EdgeNode *e;
  27. int i, k, gettop;
  28. int top = 0; // 用于栈指针下标索引
  29. int count = 0; // 用于统计输出顶点的个数
  30. int *stack; // 用于存储入度为0的顶点
  31. stack = (int *)malloc(GL->numVertexes * sizeof(int));
  32. for( i=0; i < GL->numVertexes; i++ )
  33. {
  34. if( 0 == GL->adjList[i].in )
  35. {
  36. stack[++top] = i; // 将度为0的顶点下标入栈
  37. }
  38. }
  39. // 初始化etv都为0
  40. top2 = 0;
  41. etv = (int *)malloc(GL->numVertexes*sizeof(int));
  42. for( i=0; i < GL->numVertexes; i++ )
  43. {
  44. etv[i] = 0;
  45. }
  46. stack2 = (int *)malloc(GL->numVertexes*sizeof(int));
  47. while( 0 != top )
  48. {
  49. gettop = stack[top--]; // 出栈
  50. // printf("%d -> ", GL->adjList[gettop].data);
  51. stack2[++top2] = gettop; // 保存拓扑序列顺序 C1 C2 C3 C4 .... C9
  52. count++;
  53. for( e=GL->adjList[gettop].firstedge; e; e=e->next )
  54. {
  55. k = e->adjvex;
  56. // 注意:下边这个if条件是分析整个程序的要点!
  57. // 将k号顶点邻接点的入度-1,因为他的前驱已经消除
  58. // 接着判断-1后入度是否为0,如果为0则也入栈
  59. if( !(--GL->adjList[k].in) )
  60. {
  61. stack[++top] = k;
  62. }
  63. if( (etv[gettop]+e->weight) > etv[k] )
  64. {
  65. etv[k] = etv[gettop] + e->weight;
  66. }
  67. }
  68. }
  69. if( count < GL->numVertexes ) // 如果count小于顶点数,说明存在环
  70. {
  71. return ERROR;
  72. }
  73. else
  74. {
  75. return OK;
  76. }
  77. }
  78. // 求关键路径,GL为有向图,输出GL的各项关键活动
  79. void CriticalPath(GraphAdjList GL)
  80. {
  81. EdgeNode *e;
  82. int i, gettop, k, j;
  83. int ete, lte;
  84. // 调用改进后的拓扑排序,求出etv和stack2的值
  85. TopologicalSort(GL);
  86. // 初始化ltv都为汇点的时间
  87. ltv = (int *)malloc(GL->numVertexes*sizeof(int));
  88. for( i=0; i < GL->numVertexes; i++ )
  89. {
  90. ltv[i] = etv[GL->numVertexes-1];
  91. }
  92. // 从汇点倒过来逐个计算ltv
  93. while( 0 != top2 )
  94. {
  95. gettop = stack2[top2--]; // 注意,第一个出栈是汇点
  96. for( e=GL->adjList[gettop].firstedge; e; e=e->next )
  97. {
  98. k = e->adjvex;
  99. if( (ltv[k] - e->weight) < ltv[gettop] )
  100. {
  101. ltv[gettop] = ltv[k] - e->weight;
  102. }
  103. }
  104. }
  105. // 通过etv和ltv求ete和lte
  106. for( j=0; j < GL->numVertexes; j++ )
  107. {
  108. for( e=GL->adjList[j].firstedge; e; e=e->next )
  109. {
  110. k = e->adjvex;
  111. ete = etv[j];
  112. lte = ltv[k] - e->weight;
  113. if( ete == lte )
  114. {
  115. printf("<v%d,v%d> length: %d , ", GL->adjList[j].data, GL->adjList[k].data, e->weight );
  116. }
  117. }
  118. }
  119. }