本博客的代碼的思想和圖片參考:好大學慕課浙江大學陳越老師、何欽銘老師的《數據結構》node
拓撲排序git
首先咱們來舉個例子說明:計算機專業的排課算法
課程號 課程名稱預修課程數據庫
C1 程序設計基礎無網絡
C2 離散數學無數據結構
C3 數據結構 C1, C2ide
C4 微積分(一) 無學習
C5 微積分(二) C4測試
C6 線性代數 C5ui
C7 算法分析與設計 C3
C8 邏輯與計算機設計基礎無
C9 計算機組成 C8
C10 操做系統 C7, C9
C11 編譯原理 C7, C9
C12 數據庫 C7
C13 計算理論 C2
C14 計算機網絡 C10
C15 數值分析 C6
1.拓撲序:若是圖中從V到W有一條有向路徑,則V必定排在W以前。知足此條件的頂點序列稱爲一個拓撲序。
2.得到一個拓撲序的過程就是拓撲排序
3.AOV若是有合理的拓撲序,則一定是有向無環圖(Directed Acyclic Graph, DAG)
若是在一個圖中有環路,那麼,他的拓撲排序是木有的,由於下面的理論是不可能的。
首先咱們須要根據給的關係表構建一張有向圖,在有向圖中,咱們能夠吧課程編號設置爲頂點,若是該課程有直接的預修課程,咱們讓直接的預修課程指向該課程。下面是上面的計算機排課的有向圖表示。
咱們先找出圖中沒有入度的頂點並進行打印(記錄),在初始狀況下,有C1 C2 C8 C4 能夠記錄,而後在記錄完之後,咱們刪除剛纔記錄和頂點和邊。依次的記錄或者輸出輸出以下
C1 C2 C8 C4
C3 C13 C9 C5
C7 C6
C12 C10 C11 C15
C14
void TopSort()
{
for ( cnt = 0; cnt < |V|; cnt++ ) {
V = 未輸出的入度爲0的頂點; /* O(|V|) */
if ( 這樣的V不存在 ) {
Error ( 「圖中有迴路」 );
break;
}
輸出V,或者記錄V的輸出序號;
for ( V 的每一個鄰接點 W )
Indegree[W]––;
}
}
上面的僞代碼的介紹:
1.當尚未輸出(記錄)到V個頂點時,就退出了,表示圖有迴路
2.如何實現刪除已經記錄的頂點--->對V進行一次記錄,更新其鄰接點的入度減一
3.如何實現「未輸出的入度爲0的頂點」若是每次都對全部的頂點進行以此遍歷,那麼次算法的時間複雜度爲T=O(v^2),這能夠不是一個很是好的算法,如何進行改進
咱們能夠創建一個容器,在開始或者每次入度減一時,檢查是否有節點的入度變爲0,若是有,就把該節點放入一個容器裏面。這樣這部操做就能夠變成一個常數。
下面是改進之後的僞代碼:
void TopSort()
{
for ( 圖中每一個頂點 V )
If ( Indegree[V]==0 )
Enqueue( V, Q );
while ( !IsEmpty(Q) ) {
V = Dequeue( Q );
輸出V,或者記錄V的輸出序號; cnt++;
for ( V 的每一個鄰接點 W )
if ( ––Indegree[W]==0 )
Enqueue( W, Q );
}
if ( cnt != |V| )
Error( 「圖中有迴路」 );
}
改進後的算法時間複雜的爲T=O(V+E)
此算法還能夠用來檢查有向無環圖DAG(Directed Acyclic Graph)
AOE(Activity On Edge)網絡:通常用於安排項目的工序
上面的說的都是理論,讓咱們來作一下練習吧
Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N−1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i
-th activity, three non-negative numbers are given: S[i]
, E[i]
, and L[i]
, where S[i]
is the index of the starting check point, E[i]
of the ending check point, and L[i]
the lasting time of the activity. The numbers in a line are separated by a space.
For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output "Impossible".
9 120 1 60 2 40 3 51 4 12 4 13 5 25 4 04 6 94 7 75 7 46 8 27 8 4
18
4 50 1 10 2 22 1 31 3 43 2 5
Impossible
時間限制:400ms
內存限制:64MB
代碼長度限制:16kB
判題程序:系統默認
做者:陳越
單位:浙江大學
這道題目解決的求一個工程的最先完成時間,是拓撲排序的一個變形。根據咱們上面關鍵路徑的理論知識,咱們知道,最先完成時間是上一個節點的最先完成時間+持續時間中的最大值。那麼咱們先在原來的圖的節點中添加一個字段來存儲earliest,而後初始化earliest爲0.在從隊列中取出元素時,咱們對其鄰接點的earliest進行判斷,讓鄰接點的earliest等於父節點+持續時間的最大值,並進行更新。若是最後全部的頂點都記錄完畢,咱們返回true,不然返回false(圖有迴路). 剩下的工做就是根據返回值輸出全部頂點中earliest的最大值或者Impossible。弄清楚拓撲排序之後,這道題目仍是很簡單的。
拓撲排序的源代碼:
1 /* 2 * topSort.c 3 * 4 * Created on: 2017年5月17日 5 * Author: ygh 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 10 #define MAX_VERTEX_NUM 10001 /*define the max number of the vertex*/ 11 #define INFINITY 65535 /*define double byte no negitive integer max number is 65535*/ 12 #define ERROR -1 13 14 typedef int vertex; /*define the data type of the vertex*/ 15 typedef int weightType; /*define the data type of the weight*/ 16 typedef char dataType; /*define the data type of the vertex value*/ 17 18 /*define the data structure of the Edge*/ 19 typedef struct eNode *ptrToENode; 20 typedef struct eNode { 21 vertex v1, v2; /*two vertex between the edge <v1,v2>*/ 22 weightType weight; /*the value of the edge's weight */ 23 }; 24 typedef ptrToENode edge; 25 26 /*==================A adjacent link to describe a graph=========================================*/ 27 /*define the data structure adjacent table node*/ 28 typedef struct adjNode *ptrToAdjNode; 29 typedef struct adjNode { 30 vertex adjVerx; /*the index of the vertex*/ 31 weightType weight; /*the value of the weight*/ 32 ptrToAdjNode next; /*the point to point the next node*/ 33 }; 34 35 /*define the data structure of the adjacent head*/ 36 typedef struct vNode *ptrToVNode; 37 typedef struct vNode { 38 ptrToAdjNode head; /*the point to point the adjacent table node*/ 39 dataType data; /*the space to store the name of the vertex,but some time the vertex has no names*/ 40 } adjList[MAX_VERTEX_NUM]; 41 42 /*define the data structure of graph*/ 43 typedef struct gLNode *ptrTogLNode; 44 typedef struct gLNode { 45 int vertex_number; /*the number of the vertex*/ 46 int edge_nunber; /*the number of the edge*/ 47 adjList g; /*adjacent table*/ 48 }; 49 typedef ptrTogLNode adjacentTableGraph; /*a graph show by adjacent table*/ 50 51 /* 52 create a graph given the vertex number. 53 @param vertexNum The verter number of the graph 54 @return a graph with vertex but no any egdgs 55 */ 56 adjacentTableGraph createLGraph(int vertexNum) { 57 adjacentTableGraph graph; 58 59 vertex v; 60 graph = (adjacentTableGraph) malloc(sizeof(struct gLNode)); 61 graph->vertex_number = vertexNum; 62 graph->edge_nunber = 0; 63 /*initialize the adjacent table*/ 64 for (v = 0; v < graph->vertex_number; v++) { 65 graph->g[v].head = NULL; 66 } 67 return graph; 68 } 69 70 /* 71 insert a edge to graph.We will distinct oriented graph and undirected graph 72 The e->v1 and e->v2 are the vertexs' indexs in the adjacent table 73 @param graph The graph you want to insert edge 74 @param e The edge you want to insert the graph 75 @param isOriented Whether the graph is oriented graph.If the graph is oriented 76 we will set adjacent table graph[v1]->head=v2 and set graph[v1].head=v2 77 otherwise we only set graph[v1].head=v2 78 */ 79 void insertEdgeToLink(adjacentTableGraph graph, edge e, int isOriented) { 80 /*build node<v1,v2>*/ 81 ptrToAdjNode newNode; 82 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 83 newNode->adjVerx = e->v2; 84 newNode->weight = e->weight; 85 newNode->next = graph->g[e->v1].head; 86 graph->g[e->v1].head = newNode; 87 /*if the graph is directed graph*/ 88 if (!isOriented) { 89 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 90 newNode->adjVerx = e->v1; 91 newNode->weight = e->weight; 92 newNode->next = graph->g[e->v2].head; 93 graph->g[e->v2].head = newNode; 94 } 95 } 96 97 /* 98 build a graph stored by adjacent table 99 */ 100 adjacentTableGraph buildLGraph(int isOrdered) { 101 adjacentTableGraph graph; 102 edge e; 103 vertex i; 104 int vertex_num; 105 106 scanf("%d", &vertex_num); 107 graph = createLGraph(vertex_num); 108 scanf("%d", &(graph->edge_nunber)); 109 if (graph->edge_nunber) { 110 e = (edge) malloc(sizeof(struct eNode)); 111 for (i = 0; i < graph->edge_nunber; i++) { 112 scanf("%d %d", &e->v1, &e->v2); 113 e->v1--; 114 e->v2--; 115 e->weight = 1; 116 insertEdgeToLink(graph, e, isOrdered); 117 } 118 } 119 120 return graph; 121 } 122 123 /*==============================define a queue=====================================================*/ 124 /*define a list to store the element in the queue*/ 125 typedef vertex elementType; 126 typedef struct node3 *pList; 127 typedef struct node3 { 128 elementType element; 129 struct node3 *next; 130 }; 131 132 /*define a queue to point the list*/ 133 typedef struct node4 *pQueue; 134 typedef struct node4 { 135 pList front; /*the front point to point the head of the list*/ 136 pList rear; /*the rear point to point the rear of of the list*/ 137 }; 138 139 /*create a empty list to store the queue element*/ 140 pList createEmptyList() { 141 pList list; 142 list = (pList) malloc(sizeof(struct node3)); 143 list->next = NULL; 144 return list; 145 } 146 /*create a empty queye*/ 147 pQueue createEmptyQueue() { 148 pQueue queue = (pQueue) malloc(sizeof(struct node4)); 149 queue->front = NULL; 150 queue->rear = NULL; 151 return queue; 152 } 153 154 /* 155 Wether the queue is empty 156 @param queue The queue need to adjust 157 @return If the queue is null,return 1 otherwise return 0 158 */ 159 int isQueueEmpty(pQueue queue) { 160 return (queue->front == NULL); 161 } 162 163 /* 164 Add a element to a queue,If the queue is null,we will create a new queue 165 @parama queue The queue we will add elememt to 166 @prama element The element we will add to queue 167 */ 168 void addQueue(pQueue queue, elementType element) { 169 if (isQueueEmpty(queue)) { 170 pList list = createEmptyList(); 171 list->element = element; 172 queue->front = queue->rear = list; 173 } else { 174 pList newNode = (pList) malloc(sizeof(struct node3)); 175 newNode->element = element; 176 newNode->next = queue->rear->next; 177 queue->rear->next = newNode; 178 queue->rear = newNode; 179 } 180 } 181 182 /* 183 delete a element from a queue 184 @param queue The queue will be deleted a element 185 @return The element has been deleted 186 */ 187 elementType deleteEleFromQueue(pQueue queue) { 188 if (isQueueEmpty(queue)) { 189 printf("the queue is empty,don't allow to delete elemet from it!"); 190 return -1; 191 } else { 192 pList oldNode = queue->front; 193 elementType element = oldNode->element; 194 if (queue->front == queue->rear) { 195 queue->rear = queue->front = NULL; 196 } else { 197 queue->front = queue->front->next; 198 } 199 free(oldNode); 200 return element; 201 } 202 } 203 204 /* 205 * Top sort algorithms thoughts: 206 * 1.we first initialize all vertex in-degree is zero,then we according to 207 * the graph to set the each vertex in-degree. 208 * 2.find zero in-degree vertex and put it in queue. 209 * 3.get a vertex from a queue and record its index 210 * 4.get the all adjacent vertex of the vertex and let them in-degree decrement,at this moment,if 211 * some vertex has decrease into zero,we put them into queue. 212 * 5.Execute this operation until the queue is empty 213 * 214 * @param grap A graph which use adjacent list is used to store the vertex 215 * @param topOrder A <code>vertex</code> array to store the index of the 216 * vertex about the top queue 217 * @return If the graph is no circle,indicate the top sort is correct 1 will be return 218 * otherwise will return 0 219 */ 220 int topSort(adjacentTableGraph graph, vertex topOrder[]) { 221 vertex v; 222 ptrToAdjNode w; 223 int indegree[MAX_VERTEX_NUM], vertexConter = 0; 224 /* 225 * Create a queue to store the vertex whose in-degree is zero 226 */ 227 pQueue queue = createEmptyQueue(); 228 /* 229 * Initialize topOrder 230 */ 231 for (v = 0; v < graph->vertex_number; v++) { 232 indegree[v] = 0; 233 } 234 for (v = 0; v < graph->vertex_number; v++) { 235 for (w = graph->g[v].head; w; w = w->next) { 236 indegree[w->adjVerx]++; 237 } 238 } 239 240 /* 241 * Add in-degree vertex to queue 242 */ 243 for (v = 0; v < graph->vertex_number; v++) { 244 if (indegree[v] == 0) { 245 addQueue(queue, v); 246 } 247 } 248 while (!isQueueEmpty(queue)) { 249 v = deleteEleFromQueue(queue); 250 /* 251 * Record the vertex of top sort 252 */ 253 topOrder[vertexConter++] = v; 254 for (w = graph->g[v].head; w; w = w->next) { 255 if (--indegree[w->adjVerx] == 0) { 256 addQueue(queue, w->adjVerx); 257 } 258 } 259 } 260 261 /* 262 *Adjust whether all vertexes have been recorded 263 */ 264 if (vertexConter == graph->vertex_number) { 265 return 1; 266 } else { 267 return 0; 268 } 269 } 270 271 /* 272 * Print the index of the vertex of the top sort 273 */ 274 void printTopSort(int topSort[], int length) { 275 int i; 276 printf("topSort:"); 277 for (i = 0; i < length; i++) { 278 printf("%d ", topSort[i] + 1); 279 } 280 } 281 282 int main() { 283 adjacentTableGraph graph = buildLGraph(1); 284 vertex topOrder[graph->vertex_number]; 285 int bool = topSort(graph, topOrder); 286 if (bool) { 287 printTopSort(topOrder, graph->vertex_number); 288 } else { 289 printf("the grap has a circle"); 290 } 291 return 0; 292 }
測試數據和結果:
15 14
1 3
2 3
2 13
3 7
7 12
7 10
7 11
8 9
9 11
9 10
10 14
4 5
5 6
6 15
result:
topSort:1 2 4 8 13 3 5 9 7 6 11 10 12 15 14
How Long Does It Take的源代碼
1 /* 2 * take.c 3 * 4 * Created on: 2017年5月17日 5 * Author: ygh 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 10 #define MAX_VERTEX_NUM 101 /*define the max number of the vertex*/ 11 #define INFINITY 65535 /*define double byte no negitive integer max number is 65535*/ 12 #define ERROR -1 13 14 typedef int vertex; /*define the data type of the vertex*/ 15 typedef int weightType; /*define the data type of the weight*/ 16 typedef char dataType; /*define the data type of the vertex value*/ 17 18 /*define the data structure of the Edge*/ 19 typedef struct eNode *ptrToENode; 20 typedef struct eNode { 21 vertex v1, v2; /*two vertex between the edge <v1,v2>*/ 22 weightType weight; /*the value of the edge's weight */ 23 }; 24 typedef ptrToENode edge; 25 26 /*==================A adjacent link to describe a graph=========================================*/ 27 /*define the data structure adjacent table node*/ 28 typedef struct adjNode *ptrToAdjNode; 29 typedef struct adjNode { 30 vertex adjVerx; /*the index of the vertex*/ 31 weightType weight; /*the value of the weight*/ 32 ptrToAdjNode next; /*the point to point the next node*/ 33 }; 34 35 /*define the data structure of the adjacent head*/ 36 typedef struct vNode *ptrToVNode; 37 typedef struct vNode { 38 ptrToAdjNode head; /*the point to point the adjacent table node*/ 39 dataType data; /*the space to store the name of the vertex,but some time the vertex has no names*/ 40 weightType earliest; /*The earliest data of the project*/ 41 } adjList[MAX_VERTEX_NUM]; 42 43 /*define the data structure of graph*/ 44 typedef struct gLNode *ptrTogLNode; 45 typedef struct gLNode { 46 int vertex_number; /*the number of the vertex*/ 47 int edge_nunber; /*the number of the edge*/ 48 adjList g; /*adjacent table*/ 49 }; 50 typedef ptrTogLNode adjacentTableGraph; /*a graph show by adjacent table*/ 51 52 /* 53 create a graph given the vertex number. 54 @param vertexNum The verter number of the graph 55 @return a graph with vertex but no any egdgs 56 */ 57 adjacentTableGraph createLGraph(int vertexNum) { 58 adjacentTableGraph graph; 59 60 vertex v; 61 graph = (adjacentTableGraph) malloc(sizeof(struct gLNode)); 62 graph->vertex_number = vertexNum; 63 graph->edge_nunber = 0; 64 /*initialize the adjacent table*/ 65 for (v = 0; v < graph->vertex_number; v++) { 66 graph->g[v].head = NULL; 67 graph->g[v].earliest = 0; 68 } 69 return graph; 70 } 71 72 /* 73 insert a edge to graph.We will distinct oriented graph and undirected graph 74 The e->v1 and e->v2 are the vertexs' indexs in the adjacent table 75 @param graph The graph you want to insert edge 76 @param e The edge you want to insert the graph 77 @param isOriented Whether the graph is oriented graph.If the graph is oriented 78 we will set adjacent table graph[v1]->head=v2 and set graph[v1].head=v2 79 otherwise we only set graph[v1].head=v2 80 */ 81 void insertEdgeToLink(adjacentTableGraph graph, edge e, int isOriented) { 82 /*build node<v1,v2>*/ 83 ptrToAdjNode newNode; 84 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 85 newNode->adjVerx = e->v2; 86 newNode->weight = e->weight; 87 newNode->next = graph->g[e->v1].head; 88 graph->g[e->v1].head = newNode; 89 /*if the graph is directed graph*/ 90 if (!isOriented) { 91 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 92 newNode->adjVerx = e->v1; 93 newNode->weight = e->weight; 94 newNode->next = graph->g[e->v2].head; 95 graph->g[e->v2].head = newNode; 96 } 97 } 98 99 /* 100 build a graph stored by adjacent table 101 */ 102 adjacentTableGraph buildLGraph(int isOrdered) { 103 adjacentTableGraph graph; 104 edge e; 105 vertex i; 106 int vertex_num; 107 108 scanf("%d", &vertex_num); 109 graph = createLGraph(vertex_num); 110 scanf("%d", &(graph->edge_nunber)); 111 if (graph->edge_nunber) { 112 e = (edge) malloc(sizeof(struct eNode)); 113 for (i = 0; i < graph->edge_nunber; i++) { 114 scanf("%d %d %d", &e->v1, &e->v2, &e->weight); 115 insertEdgeToLink(graph, e, isOrdered); 116 } 117 } 118 119 return graph; 120 } 121 122 /*==============================define a queue=====================================================*/ 123 /*define a list to store the element in the queue*/ 124 typedef vertex elementType; 125 typedef struct node3 *pList; 126 typedef struct node3 { 127 elementType element; 128 struct node3 *next; 129 }; 130 131 /*define a queue to point the list*/ 132 typedef struct node4 *pQueue; 133 typedef struct node4 { 134 pList front; /*the front point to point the head of the list*/ 135 pList rear; /*the rear point to point the rear of of the list*/ 136 }; 137 138 /*create a empty list to store the queue element*/ 139 pList createEmptyList() { 140 pList list; 141 list = (pList) malloc(sizeof(struct node3)); 142 list->next = NULL; 143 return list; 144 } 145 /*create a empty queye*/ 146 pQueue createEmptyQueue() { 147 pQueue queue = (pQueue) malloc(sizeof(struct node4)); 148 queue->front = NULL; 149 queue->rear = NULL; 150 return queue; 151 } 152 153 /* 154 Wether the queue is empty 155 @param queue The queue need to adjust 156 @return If the queue is null,return 1 otherwise return 0 157 */ 158 int isQueueEmpty(pQueue queue) { 159 return (queue->front == NULL); 160 } 161 162 /* 163 Add a element to a queue,If the queue is null,we will create a new queue 164 @parama queue The queue we will add elememt to 165 @prama element The element we will add to queue 166 */ 167 void addQueue(pQueue queue, elementType element) { 168 if (isQueueEmpty(queue)) { 169 pList list = createEmptyList(); 170 list->element = element; 171 queue->front = queue->rear = list; 172 } else { 173 pList newNode = (pList) malloc(sizeof(struct node3)); 174 newNode->element = element; 175 newNode->next = queue->rear->next; 176 queue->rear->next = newNode; 177 queue->rear = newNode; 178 } 179 } 180 181 /* 182 delete a element from a queue 183 @param queue The queue will be deleted a element 184 @return The element has been deleted 185 */ 186 elementType deleteEleFromQueue(pQueue queue) { 187 if (isQueueEmpty(queue)) { 188 printf("the queue is empty,don't allow to delete elemet from it!"); 189 return -1; 190 } else { 191 pList oldNode = queue->front; 192 elementType element = oldNode->element; 193 if (queue->front == queue->rear) { 194 queue->rear = queue->front = NULL; 195 } else { 196 queue->front = queue->front->next; 197 } 198 free(oldNode); 199 return element; 200 } 201 } 202 203 /* 204 * We solve this problem by top sort,but we need to update the adjacent 205 * vertex earliest value at decreasing the adjacent vertex in-degree,the 206 * earliest the max value of parent's earliest value add the weight(last time). 207 * The vertex which has no in-degree will set earliest to 0 at first time 208 * 209 * Top sort algorithms thoughts: 210 * 1.we first initialize all vertex in-degree is zero,then we according to 211 * the graph to set the each vertex in-degree. 212 * 2.find zero in-degree vertex and put it in queue. 213 * 3.get a vertex from a queue and record its index 214 * 4.get the all adjacent vertex of the vertex and let them in-degree decrement,at this moment,if 215 * some vertex has decrease into zero,we put them into queue. 216 * 5.Execute this operation until the queue is empty 217 * 218 * @param grap A graph which use adjacent list is used to store the vertex 219 * @param topOrder A <code>vertex</code> array to store the index of the 220 * vertex about the top queue 221 * @return If the graph is no circle,indicate the top sort is correct 1 will be return 222 * otherwise will return 0 223 */ 224 int getEarliestDate(adjacentTableGraph graph, vertex topOrder[]) { 225 vertex v; 226 ptrToAdjNode w; 227 int indegree[MAX_VERTEX_NUM], vertexConter = 0; 228 /* 229 * Create a queue to store the vertex whose in-degree is zero 230 */ 231 pQueue queue = createEmptyQueue(); 232 /* 233 * Initialize topOrder 234 */ 235 for (v = 0; v < graph->vertex_number; v++) { 236 indegree[v] = 0; 237 } 238 for (v = 0; v < graph->vertex_number; v++) { 239 for (w = graph->g[v].head; w; w = w->next) { 240 indegree[w->adjVerx]++; 241 } 242 } 243 244 /* 245 * Add in-degree vertex to queue 246 */ 247 for (v = 0; v < graph->vertex_number; v++) { 248 if (indegree[v] == 0) { 249 addQueue(queue, v); 250 graph->g[v].earliest = 0; 251 } 252 } 253 while (!isQueueEmpty(queue)) { 254 v = deleteEleFromQueue(queue); 255 /* 256 * Record the vertex of top sort 257 */ 258 topOrder[vertexConter++] = v; 259 for (w = graph->g[v].head; w; w = w->next) { 260 /* 261 * Update the adjacent vertex's earliest 262 */ 263 if ((graph->g[v].earliest + w->weight) 264 > (graph->g[w->adjVerx].earliest)) { 265 graph->g[w->adjVerx].earliest = graph->g[v].earliest 266 + w->weight; 267 } 268 if (--indegree[w->adjVerx] == 0) { 269 addQueue(queue, w->adjVerx); 270 } 271 } 272 } 273 274 /* 275 *Adjust whether all vertexes have been recorded 276 */ 277 if (vertexConter == graph->vertex_number) { 278 return 1; 279 } else { 280 return 0; 281 } 282 } 283 284 /* 285 * Get the earliest max value from all vertex.we search each vertex and find the max earliest 286 * and return 287 * @param grap A graph which use adjacent list is used to store the vertex 288 */ 289 int getEarliestTime(adjacentTableGraph graph) { 290 weightType maxTime = -1; 291 vertex v; 292 for (v = 0; v < graph->vertex_number; v++) { 293 if (graph->g[v].earliest > maxTime) { 294 maxTime = graph->g[v].earliest; 295 } 296 } 297 return maxTime; 298 } 299 300 int main() { 301 adjacentTableGraph graph = buildLGraph(1); 302 vertex topOrder[graph->vertex_number]; 303 int bool = getEarliestDate(graph, topOrder); 304 if (bool) { 305 printf("%d\n", getEarliestTime(graph)); 306 } else { 307 printf("Impossible"); 308 } 309 return 0; 310 }
還有一道練習題滿分30分,我得了23分,主體算法應該是對的,某些細節方面估計還有點問題
假定一個工程項目由一組子任務構成,子任務之間有的能夠並行執行,有的必須在完成了其它一些子任務後才能執行。「任務調度」包括一組子任務、以及每一個子任務能夠執行所依賴的子任務集。
好比完成一個專業的全部課程學習和畢業設計能夠當作一個本科生要完成的一項工程,各門課程能夠當作是子任務。有些課程能夠同時開設,好比英語和C程序設計,它們沒有必須先修哪門的約束;有些課程則不能夠同時開設,由於它們有前後的依賴關係,好比C程序設計和數據結構兩門課,必須先學習前者。
可是須要注意的是,對一組子任務,並非任意的任務調度都是一個可行的方案。好比方案中存在「子任務A依賴於子任務B,子任務B依賴於子任務C,子任務C又依賴於子任務A」,那麼這三個任務哪一個都不能先執行,這就是一個不可行的方案。
任務調度問題中,若是還給出了完成每一個子任務須要的時間,則咱們能夠算出完成整個工程須要的最短期。在這些子任務中,有些任務即便推遲幾天完成,也不會影響全局的工期;可是有些任務必須準時完成,不然整個項目的工期就要所以延誤,這種任務就叫「關鍵活動」。
請編寫程序斷定一個給定的工程項目的任務調度是否可行;若是該調度方案可行,則計算完成整個工程項目須要的最短期,並輸出全部的關鍵活動。
輸入第1行給出兩個正整數N(≤100)和M,其中N是任務交接點(即銜接相互依賴的兩個子任務的節點,例如:若任務2要在任務1完成後纔開始,則兩任務之間必有一個交接點)的數量。交接點按1~N編號,M是子任務的數量,依次編號爲1~M。隨後M行,每行給出了3個正整數,分別是該任務開始和完成涉及的交接點編號以及該任務所需的時間,整數間用空格分隔。
若是任務調度不可行,則輸出0;不然第1行輸出完成整個工程項目須要的時間,第2行開始輸出全部關鍵活動,每一個關鍵活動佔一行,按格式「V->W」輸出,其中V和W爲該任務開始和完成涉及的交接點編號。關鍵活動輸出的順序規則是:任務開始的交接點編號小者優先,起點編號相同時,與輸入時任務的順序相反。
7 81 2 41 3 32 4 53 4 34 5 14 6 65 7 56 7 2
171->22->44->66->7
1.先按照5.1問題計算出每一個節點的earliest,並找出最大值,這樣就計算出17
2.
因爲須要輸入關鍵路徑,而關鍵路徑的計算和
latest
有關,咱們必須先計算出
latest
。
3.
咱們知道,最後完工的頂點出度爲
0
,而且他的
earliest
等於
latest
,因此咱們先初始化出度爲
0
的
latest
,讓其等於
earliest
。而後咱們找其父節點,讓父節點的
latest
爲子節點的
latest
減去權重
(
持續時間
)
,去全部子節點中的最小值。這樣咱們能夠成功的計算出每一個節點的
latest
。而後如何判斷是關鍵節點呢。
4.
判斷是否爲關鍵節點,若是子節點的
latest-
父節點的
earliest-
鏈接邊的權重
==0
那麼這條邊爲關鍵路徑
,不然不是,進行對應的輸出便可。
下面是個人代碼,沒有經過所有測試點,若是你知道緣由,能夠在下面評論告訴我哦
1 /* 2 * keyPath.c 3 * 4 * Created on: 2017年5月17日 5 * Author: ygh 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #define MAX_VERTEX_NUM 100 /*define the max number of the vertex*/ 12 #define INFINITY 65535 /*define double byte no negitive integer max number is 65535*/ 13 #define ERROR -1 14 15 typedef int vertex; /*define the data type of the vertex*/ 16 typedef int weightType; /*define the data type of the weight*/ 17 typedef char dataType; /*define the data type of the vertex value*/ 18 19 vertex inputOrder[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; 20 /*define the data structure of the Edge*/ 21 typedef struct eNode *ptrToENode; 22 typedef struct eNode { 23 vertex v1, v2; /*two vertex between the edge <v1,v2>*/ 24 weightType weight; /*the value of the edge's weight */ 25 }; 26 typedef ptrToENode edge; 27 28 /*==================A adjacent link to describe a graph=========================================*/ 29 /*define the data structure adjacent table node*/ 30 typedef struct adjNode *ptrToAdjNode; 31 typedef struct adjNode { 32 vertex adjVerx; /*the index of the vertex*/ 33 weightType weight; /*the value of the weight*/ 34 ptrToAdjNode next; /*the point to point the next node*/ 35 }; 36 37 /*define the data structure of the adjacent head*/ 38 typedef struct vNode *ptrToVNode; 39 typedef struct vNode { 40 ptrToAdjNode head; /*the point to point the adjacent table node*/ 41 dataType data; /*the space to store the name of the vertex,but some time the vertex has no names*/ 42 weightType earliest; /*The earliest data of the project*/ 43 weightType latest; /*The latest time*/ 44 } adjList[MAX_VERTEX_NUM]; 45 46 /*define the data structure of graph*/ 47 typedef struct gLNode *ptrTogLNode; 48 typedef struct gLNode { 49 int vertex_number; /*the number of the vertex*/ 50 int edge_nunber; /*the number of the edge*/ 51 adjList g; /*adjacent table*/ 52 }; 53 typedef ptrTogLNode adjacentTableGraph; /*a graph show by adjacent table*/ 54 55 /* 56 create a graph given the vertex number. 57 @param vertexNum The verter number of the graph 58 @return a graph with vertex but no any egdgs 59 */ 60 adjacentTableGraph createLGraph(int vertexNum) { 61 adjacentTableGraph graph; 62 63 vertex v; 64 graph = (adjacentTableGraph) malloc(sizeof(struct gLNode)); 65 graph->vertex_number = vertexNum; 66 graph->edge_nunber = 0; 67 /*initialize the adjacent table*/ 68 for (v = 0; v < graph->vertex_number; v++) { 69 graph->g[v].head = NULL; 70 graph->g[v].earliest = 0; 71 graph->g[v].latest = INFINITY; 72 } 73 return graph; 74 } 75 76 /* 77 insert a edge to graph.We will distinct oriented graph and undirected graph 78 The e->v1 and e->v2 are the vertexs' indexs in the adjacent table 79 @param graph The graph you want to insert edge 80 @param e The edge you want to insert the graph 81 @param isOriented Whether the graph is oriented graph.If the graph is oriented 82 we will set adjacent table graph[v1]->head=v2 and set graph[v1].head=v2 83 otherwise we only set graph[v1].head=v2 84 */ 85 void insertEdgeToLink(adjacentTableGraph graph, edge e, int isOriented) { 86 /*build node<v1,v2>*/ 87 ptrToAdjNode newNode; 88 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 89 newNode->adjVerx = e->v2; 90 newNode->weight = e->weight; 91 newNode->next = graph->g[e->v1].head; 92 graph->g[e->v1].head = newNode; 93 /*if the graph is directed graph*/ 94 if (!isOriented) { 95 newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode)); 96 newNode->adjVerx = e->v1; 97 newNode->weight = e->weight; 98 newNode->next = graph->g[e->v2].head; 99 graph->g[e->v2].head = newNode; 100 } 101 } 102 103 /* 104 build a graph stored by adjacent table 105 */ 106 adjacentTableGraph buildLGraph(int isOrdered) { 107 adjacentTableGraph graph; 108 edge e; 109 vertex i; 110 int vertex_num; 111 112 scanf("%d", &vertex_num); 113 graph = createLGraph(vertex_num); 114 scanf("%d", &(graph->edge_nunber)); 115 if (graph->edge_nunber) { 116 e = (edge) malloc(sizeof(struct eNode)); 117 for (i = 0; i < graph->edge_nunber; i++) { 118 scanf("%d %d %d", &e->v1, &e->v2, &e->weight); 119 e->v1--; 120 e->v2--; 121 insertEdgeToLink(graph, e, isOrdered); 122 } 123 } 124 125 return graph; 126 } 127 128 /*==============================define a queue=====================================================*/ 129 /*define a list to store the element in the queue*/ 130 typedef vertex elementType; 131 typedef struct node3 *pList; 132 typedef struct node3 { 133 elementType element; 134 struct node3 *next; 135 }; 136 137 /*define a queue to point the list*/ 138 typedef struct node4 *pQueue; 139 typedef struct node4 { 140 pList front; /*the front point to point the head of the list*/ 141 pList rear; /*the rear point to point the rear of of the list*/ 142 }; 143 144 /*create a empty list to store the queue element*/ 145 pList createEmptyList() { 146 pList list; 147 list = (pList) malloc(sizeof(struct node3)); 148 list->next = NULL; 149 return list; 150 } 151 /*create a empty queye*/ 152 pQueue createEmptyQueue() { 153 pQueue queue = (pQueue) malloc(sizeof(struct node4)); 154 queue->front = NULL; 155 queue->rear = NULL; 156 return queue; 157 } 158 159 /* 160 Wether the queue is empty 161 @param queue The queue need to adjust 162 @return If the queue is null,return 1 otherwise return 0 163 */ 164 int isQueueEmpty(pQueue queue) { 165 return (queue->front == NULL); 166 } 167 168 /* 169 Add a element to a queue,If the queue is null,we will create a new queue 170 @parama queue The queue we will add elememt to 171 @prama element The element we will add to queue 172 */ 173 void addQueue(pQueue queue, elementType element) { 174 if (isQueueEmpty(queue)) { 175 pList list = createEmptyList(); 176 list->element = element; 177 queue->front = queue->rear = list; 178 } else { 179 pList newNode = (pList) malloc(sizeof(struct node3)); 180 newNode->element = element; 181 newNode->next = queue->rear->next; 182 queue->rear->next = newNode; 183 queue->rear = newNode; 184 } 185 } 186 187 /* 188 delete a element from a queue 189 @param queue The queue will be deleted a element 190 @return The element has been deleted 191 */ 192 elementType deleteEleFromQueue(pQueue queue) { 193 if (isQueueEmpty(queue)) { 194 printf("the queue is empty,don't allow to delete elemet from it!"); 195 return -1; 196 } else { 197 pList oldNode = queue->front; 198 elementType element = oldNode->element; 199 if (queue->front == queue->rear) { 200 queue->rear = queue->front = NULL; 201 } else { 202 queue->front = queue->front->next; 203 } 204 free(oldNode); 205 return element; 206 } 207 } 208 209 /* 210 * We solve this problem by top sort,but we need to update the adjacent 211 * vertex earliest value at decreasing the adjacent vertex in-degree,the 212 * earliest the max value of parent's earliest value add the weight(last time). 213 * The vertex which has no in-degree will set earliest to 0 at first time 214 * 215 * Top sort algorithms thoughts: 216 * 1.we first initialize all vertex in-degree is zero,then we according to 217 * the graph to set the each vertex in-degree. 218 * 2.find zero in-degree vertex and put it in queue. 219 * 3.get a vertex from a queue and record its index 220 * 4.get the all adjacent vertex of the vertex and let them in-degree decrement,at this moment,if 221 * some vertex has decrease into zero,we put them into queue. 222 * 5.Execute this operation until the queue is empty 223 * 224 * @param grap A graph which use adjacent list is used to store the vertex 225 * @param topOrder A <code>vertex</code> array to store the index of the 226 * vertex about the top queue 227 * @return If the graph is no circle,indicate the top sort is correct 1 will be return 228 * otherwise will return 0 229 */ 230 int getEarliestDate(adjacentTableGraph graph, vertex topOrder[]) { 231 vertex v; 232 ptrToAdjNode w; 233 int indegree[MAX_VERTEX_NUM], vertexConter = 0; 234 /* 235 * Create a queue to store the vertex whose in-degree is zero 236 */ 237 pQueue queue = createEmptyQueue(); 238 /* 239 * Initialize topOrder 240 */ 241 for (v = 0; v < graph->vertex_number; v++) { 242 indegree[v] = 0; 243 } 244 for (v = 0; v < graph->vertex_number; v++) { 245 for (w = graph->g[v].head; w; w = w->next) { 246 indegree[w->adjVerx]++; 247 } 248 } 249 250 /* 251 * Add in-degree vertex to queue 252 */ 253 for (v = 0; v < graph->vertex_number; v++) { 254 if (indegree[v] == 0) { 255 addQueue(queue, v); 256 graph->g[v].earliest = 0; 257 } 258 } 259 while (!isQueueEmpty(queue)) { 260 v = deleteEleFromQueue(queue); 261 /* 262 * Record the vertex of top sort 263 */ 264 topOrder[vertexConter++] = v; 265 for (w = graph->g[v].head; w; w = w->next) { 266 if ((graph->g[v].earliest + w->weight) 267 > (graph->g[w->adjVerx].earliest)) { 268 graph->g[w->adjVerx].earliest = graph->g[v].earliest 269 + w->weight; 270 } 271 if (--indegree[w->adjVerx] == 0) { 272 addQueue(queue, w->adjVerx); 273 } 274 } 275 } 276 277 /* 278 *Adjust whether all vertexes have been recorded 279 */ 280 if (vertexConter == graph->vertex_number) { 281 return 1; 282 } else { 283 return 0; 284 } 285 } 286 287 /* 288 * You know ,we need to let these vertex whose out-degree is zero 289 * latest equal earliest.These whose out-degree is zero is the vertex which 290 * the project's finish vertex 291 * @param grap A graph which use adjacent list is used to store the vertex 292 */ 293 void initLatest(adjacentTableGraph graph) { 294 vertex v; 295 ptrToAdjNode w; 296 vertex outdegree[graph->vertex_number]; 297 for (v = 0; v < graph->vertex_number; v++) { 298 outdegree[v] = 0; 299 } 300 for (v = 0; v < graph->vertex_number; v++) { 301 for (w = graph->g[v].head; w; w = w->next) { 302 outdegree[v]++; 303 } 304 } 305 /* 306 *find out-degree vertex and set them latest equal earliest 307 */ 308 for (v = 0; v < graph->vertex_number; v++) { 309 if (outdegree[v] == 0) { 310 graph->g[v].latest = graph->g[v].earliest; 311 } 312 } 313 } 314 315 /* 316 * Calculate the the latest by the earliest and the top sort result 317 * From the class,we can know the latest value is minimal value amount the child vertex's latest 318 * minus the weight(we use the weight as the lasting time).Before caller this method,we have 319 * initialize the terminal vertex latest value.You can see the method above. 320 *@param grap A graph which use adjacent list is used to store the vertex 321 *@param topOrder a <code>vertex</code> array to store the top sort result 322 * 323 */ 324 void calculateTheLatest(adjacentTableGraph graph, vertex topOrder[]) { 325 int length = graph->vertex_number, i; 326 ptrToAdjNode w; 327 vertex v; 328 for (i = length - 1; i >= 0; i--) { 329 for (v = 0; v < graph->vertex_number; v++) { 330 for (w = graph->g[v].head; w; w = w->next) { 331 if (w->adjVerx == topOrder[i]) { 332 if (graph->g[v].latest 333 > (graph->g[topOrder[i]].latest - w->weight)) { 334 graph->g[v].latest = graph->g[topOrder[i]].latest 335 - w->weight; 336 } 337 338 } 339 } 340 } 341 } 342 } 343 344 /* 345 * Print the key path,we know when child vertex's latest minus parent vertex's earliest 346 * and minus the weight(we use the weight as the lasting time),if the result is equal zero 347 * indicating this is key path.we print them. 348 *@param grap A graph which use adjacent list is used to store the vertex 349 */ 350 void recordKeyActivity(adjacentTableGraph graph) { 351 vertex v; 352 ptrToAdjNode w; 353 for (v = 0; v < graph->vertex_number; v++) { 354 for (w = graph->g[v].head; w; w = w->next) { 355 if (graph->g[w->adjVerx].latest - graph->g[v].earliest 356 == w->weight) { 357 printf("%d->%d\n", v + 1, w->adjVerx + 1); 358 } 359 } 360 } 361 } 362 363 /* 364 * Get the earliest max value from all vertex.we search each vertex and find the max earliest 365 * and return 366 * @param grap A graph which use adjacent list is used to store the vertex 367 */ 368 int getEarliestTime(adjacentTableGraph graph) { 369 weightType maxTime = -1; 370 vertex v; 371 for (v = 0; v < graph->vertex_number; v++) { 372 if (graph->g[v].earliest > maxTime) { 373 maxTime = graph->g[v].earliest; 374 } 375 } 376 return maxTime; 377 } 378 379 /* 380 * Access graph vertex by the index of the vertex 381 */ 382 void visit(adjacentTableGraph graph, vertex v) { 383 printf("%d %d %d\n", v, graph->g[v].earliest, graph->g[v].latest); 384 } 385 386 /* 387 Depth first search a graph 388 @param graph The graph need to search 389 @param startPoint The fisrt point we start search the graph 390 @paran int *visited The array we use to tag the vertex we has accessed. 391 */ 392 void DFS(adjacentTableGraph graph, vertex startPoint, int *visited) { 393 ptrToAdjNode p; 394 visit(graph, startPoint); 395 visited[startPoint] = 1; 396 for (p = graph->g[startPoint].head; p; p = p->next) { 397 if (visited[p->adjVerx] == 0) { 398 DFS(graph, p->adjVerx, visited); 399 } 400 } 401 } 402 403 /* 404 * Fill a array with value 405 * @param arr The array need to be filled 406 * @param length The length of the array 407 * @param filledValue The value the array will be filled 408 */ 409 void fullArray(int *arr, int length, int filledValue) { 410 int i; 411 for (i = 0; i < length; i++) { 412 arr[i] = filledValue; 413 } 414 } 415 416 int main() { 417 adjacentTableGraph graph = buildLGraph(1); 418 vertex topOrder[graph->vertex_number]; 419 vertex keyActivities[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; 420 int bool = getEarliestDate(graph, topOrder); 421 if (bool) { 422 printf("%d\n", getEarliestTime(graph)); 423 } else { 424 printf("0\n"); 425 } 426 initLatest(graph); 427 calculateTheLatest(graph, topOrder); 428 recordKeyActivity(graph); 429 return 0; 430 }
PTA的測試結果圖: