08-图9 关键活动 (30 分)
假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。
比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。
但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。
任务调度问题中,如果还给出了完成每个子任务需要的时间,则我们可以算出完成整个工程需要的最短时间。在这些子任务中,有些任务即使推迟几天完成,也不会影响全局的工期;但是有些任务必须准时完成,否则整个项目的工期就要因此延误,这种任务就叫“关键活动”。
请编写程序判定一个给定的工程项目的任务调度是否可行;如果该调度方案可行,则计算完成整个工程项目需要的最短时间,并输出所有的关键活动。
输入格式:
输入第1行给出两个正整数N(≤)和M,其中N是任务交接点(即衔接相互依赖的两个子任务的节点,例如:若任务2要在任务1完成后才开始,则两任务之间必有一个交接点)的数量。交接点按1~N编号,M是子任务的数量,依次编号为1~M。随后M行,每行给出了3个正整数,分别是该任务开始和完成涉及的交接点编号以及该任务所需的时间,整数间用空格分隔。
输出格式:
如果任务调度不可行,则输出0;否则第1行输出完成整个工程项目需要的时间,第2行开始输出所有关键活动,每个关键活动占一行,按格式“V->W”输出,其中V和W为该任务开始和完成涉及的交接点编号。关键活动输出的顺序规则是:任务开始的交接点编号小者优先,起点编号相同时,与输入时任务的顺序相反。
输入样例:
7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2
输出样例:
17 1->2 2->4 4->6 6->7
1 #include <stdlib.h> 2 #include <cstdio> 3 #include <queue> 4 #define MaxVertexNum 102 5 #define INFINITY 65536 6 using namespace std; 7 8 typedef int Vertex; 9 typedef int WeightType; 10 typedef int DataType; 11 12 int Earliest[MaxVertexNum]; 13 int Latest[MaxVertexNum]; 14 int KeyEdge[MaxVertexNum][MaxVertexNum]; 15 16 17 typedef struct ENode *Edge; 18 struct ENode{ 19 Vertex V1, V2; 20 WeightType Weight; 21 }; 22 23 typedef struct AdjVNode *PtrToAdjVNode; 24 struct AdjVNode{ 25 Vertex AdjV; 26 WeightType Weight; 27 PtrToAdjVNode Next; 28 int flag; 29 }; 30 31 typedef struct Vnode{ 32 PtrToAdjVNode FirstEdge; 33 34 } AdjList[MaxVertexNum]; /* AdjListÊÇÁÚ½Ó±íÀàÐÍ */ 35 36 37 typedef struct GNode *LGraph; 38 struct GNode{ 39 int Nv; 40 int Ne; 41 AdjList G; 42 WeightType Matrix[MaxVertexNum][MaxVertexNum]; 43 }; 44 45 46 LGraph CreateGraph( int VertexNum ); 47 void InsertEdge( LGraph Graph, Edge E ); 48 LGraph BuildGraph(); 49 50 bool topSort(LGraph Graph); 51 int findEarliest(LGraph Graph); 52 53 void bottomSort(LGraph Graph, int EarilestTime); 54 void outPut(LGraph Graph, int DDL); 55 56 57 int main() { 58 LGraph Graph = BuildGraph(); 59 60 if( !topSort(Graph) ) printf("0\n"); 61 else { 62 int DDL = findEarliest(Graph); 63 64 bottomSort(Graph, DDL); 65 66 67 68 outPut(Graph, DDL); 69 } 70 71 72 73 } 74 75 76 LGraph CreateGraph( int VertexNum ) 77 { 78 Vertex V, W; 79 LGraph Graph; 80 81 Graph = (LGraph)malloc( sizeof(struct GNode) ); 82 Graph->Nv = VertexNum; 83 Graph->Ne = 0; 84 85 for (V=0; V<Graph->Nv; V++) 86 Graph->G[V].FirstEdge = NULL; 87 88 for (V = 0; V<Graph->Nv; V++){ 89 for (W = 0; W<Graph->Nv; W++) { 90 Graph->Matrix[V][W] = INFINITY; 91 KeyEdge[V][W] = 1; 92 } 93 } 94 return Graph; 95 } 96 void InsertEdge( LGraph Graph, Edge E ) 97 { 98 PtrToAdjVNode newNode = new AdjVNode; 99 newNode->Weight = E->Weight; 100 newNode->AdjV = E->V2; 101 102 newNode->Next = Graph->G[E->V1].FirstEdge; 103 Graph->G[E->V1].FirstEdge = newNode; 104 105 } 106 LGraph BuildGraph() 107 { 108 LGraph Graph; 109 int Nv; 110 Edge E; 111 Vertex V; 112 113 scanf("%d", &Nv); 114 Graph = CreateGraph(Nv); 115 116 scanf("%d", &(Graph->Ne)); 117 118 if(Graph->Ne) { 119 E = new ENode; 120 for(int i=0; i<Graph->Ne; i++) { 121 scanf("%d %d %d", &(E->V1), &(E->V2), &(E->Weight)); 122 E->V1--; E->V2--; 123 Graph->Matrix[E->V2][E->V1] = E->Weight; 124 InsertEdge(Graph, E); 125 } 126 } 127 128 129 return Graph; 130 131 } 132 133 bool topSort(LGraph Graph) 134 { 135 int cnt; 136 int Indegree[MaxVertexNum]; 137 Vertex V; 138 queue<Vertex> Q; 139 140 cnt = 0; 141 for( V=0; V<Graph->Nv; V++) {Indegree[V] = 0; Earliest[V] = 0; } 142 143 for( V = 0; V < Graph->Nv; V++) { 144 for(PtrToAdjVNode W = Graph->G[V].FirstEdge; W; W=W->Next) { 145 Indegree[W->AdjV]++; 146 147 } 148 } 149 for(V=0; V<Graph->Nv; V++) if(Indegree[V] == 0) Q.push(V); 150 151 while(!Q.empty()) { 152 V = Q.front(); 153 Q.pop(); 154 cnt++; 155 156 for(PtrToAdjVNode W = Graph->G[V].FirstEdge; W; W=W->Next) { 157 if(--Indegree[W->AdjV] == 0) Q.push(W->AdjV); 158 if(Earliest[W->AdjV] < W->Weight + Earliest[V]) 159 { 160 Earliest[W->AdjV] = W->Weight + Earliest[V]; 161 162 } 163 164 } 165 166 167 } 168 169 if(cnt != Graph->Nv) return false; 170 return true; 171 172 173 } 174 int findEarliest(LGraph Graph) 175 { 176 177 Vertex V, MaxV; 178 int compTime; 179 compTime = Earliest[0]; 180 181 for(V = 1; V < Graph->Nv; V++) { 182 if(Earliest[V] > compTime) {compTime = Earliest[V]; MaxV = V; } 183 } 184 185 return compTime; 186 187 188 189 } 190 void bottomSort(LGraph Graph, int earlyTime) 191 { 192 int OutDegree2[MaxVertexNum]; 193 int cnt; 194 Vertex V; 195 queue<Vertex> Q; 196 197 cnt = 0; 198 199 for (V = 0; V < Graph->Nv; V++) { 200 OutDegree2[V] = 0; 201 Latest[V] = INFINITY; 202 } 203 204 for( V = 0; V < Graph->Nv; V++) { 205 for(PtrToAdjVNode W = Graph->G[V].FirstEdge; W; W=W->Next) { 206 OutDegree2[V]++; 207 } 208 if (!OutDegree2[V]) { 209 Latest[V] = earlyTime; 210 } 211 } 212 213 for(V=0; V<Graph->Nv; V++) if(OutDegree2[V] == 0) Q.push(V); 214 215 while(!Q.empty()) { 216 217 V = Q.front(); 218 Q.pop(); 219 cnt++; 220 221 for (Vertex W = 0; W<Graph->Nv; W++) { 222 223 if(Graph->Matrix[V][W] != INFINITY) { 224 if (--OutDegree2[W] == 0) { 225 Q.push(W); 226 } 227 228 if (Latest[V] - Graph->Matrix[V][W] < Latest[W]) { 229 Latest[W] = Latest[V] - Graph->Matrix[V][W]; 230 } 231 232 } 233 234 } 235 236 237 238 } 239 for (Vertex V = 0; V<Graph->Nv; V++) { 240 for (Vertex W = 0; W < Graph->Nv; W++) { 241 KeyEdge[V][W] = Latest[W] - Earliest[V] - Graph->Matrix[W][V]; 242 } 243 } 244 245 246 247 } 248 void outPut(LGraph Graph, int DDL) 249 { 250 printf("%d\n", DDL); 251 for (Vertex V = 0; V<Graph->Nv; V++) { 252 for (PtrToAdjVNode W = Graph->G[V].FirstEdge; W; W=W->Next) { 253 if (KeyEdge[V][W->AdjV] == 0) { 254 printf("%d->%d\n", V+1, W->AdjV+1); 255 } 256 } 257 } 258 }