AOV Network
AOV는 Activity On Vertex의 약자입니다. 즉 정점이 Activity 작업을 나타내고, 간선이 작업간의 우선순위 관계를 나타내는 방향 그래프입니다.

위의 그래프의 각 정점이 작업을 나타내다고 해 봅시다. 1번 작업이 끝나면 3, 4번 작업을 할 수 있고, 3, 4번 작업이 끝나야 5번 작업을 할 수 있고, 2번 작업이 끝나야 6번 작업을 할 수 있고, 마지막으로 5, 6번 작업이 끝나면 7번을 할 수 있는 식입니다.
predecessor는 어떤 작업을 하기 전에 해야하는 작업을 의미하고, successor는 어떤 작업을 하고 나서 해야 할 작업을 의미합니다. 앞에 immediate가 붙으면 바로 전, 바로 후의 작업을 의미합니다.
AOV네트워크에서 중요한 것은 어떤 순서로 일을 끝낼 것이냐? 입니다. 이를 위해 Topological sort라는 것이 존재합니다. BFS또는 DFS를 이용하여 구현할 수 있습니다.

위 그림에서의 위 개념을 정해 보도록 하겠습니다.
- C3과 C6은 C7의 immediate predecessor이라고 할 수 있습니다.
- C9, C10, C12, C13은 C7의 immediate successor라고 할 수 있습니다.
- C14는 C3의 successor이지만 immediate success라고 할 순 없습니다.
그리고 Topological orders를 찾는 방법을 알아보도록 하겠습니다.
- 첫번째로 predecessor가 없는 vertex를 찾습니다.
- 그리고 위에서 찾은 vertex를 이와 연결되어 있는 edge와 함꼐 삭제 합니다.

위의 예시를 적용해 보면 위 그래프의 topological orders는 0, 3, 2, 5, 1, 4가 될 수 있습니다. 이 외에도 더 많은 topological orders가 존재할 수 있습니다.
/AOV.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_VERTICES 100 typedef struct node_ { int vertex; struct node_ *link; } node, *nodePointer; typedef struct hdnodes { int count; nodePointer link; } hdnodes; hdnodes graph[MAX_VERTICES]; void topSort(hdnodes graph[], int n) { int i, j, k, top; nodePointer ptr; top = -1; for (i = 0; i < n; i++) { // graph[i].count의 값이 0이면 predecessor가 없는 것이므로 // i의 count를 -1로 하고 top의 값을 i로 한다. if (!graph[i].count) { graph[i].count = top; top = i; } } for (i = 0; i < n; i++) { // 만약 top if (top == -1) { fprintf(stderr, "\nNetwork has a cycle. Sort terminated. \n"); exit(EXIT_FAILURE); } else { j = top; top = graph[top].count; printf("%3d", j); for (ptr = graph[i].link; ptr; ptr = ptr->link) { k = ptr->vertex; graph[k].count--; if (!graph[k].count) { graph[k].count = top; top = k; } } } } } int main(void) { FILE *fp_read = fopen("input.txt", "r"); if (fp_read == NULL) { fprintf(stderr, "File Open Error!"); exit(EXIT_FAILURE); } int vertexNum; fscanf(fp_read, "%d", &vertexNum); int **input = malloc(sizeof(int *) * vertexNum); for (int i = 0; i < vertexNum; i++) input[i] = malloc(sizeof(int) * vertexNum); int num; for (int i = 0; i < vertexNum; i++) for (int j = 0; j < vertexNum; j++) fscanf(fp_read, "%d", &input[i][j]); nodePointer tempNode; nodePointer tempNode2; for (int i = 0; i < vertexNum; i++) { graph[i].link = NULL; for (int j = 0; j < vertexNum; j++) { if (input[i][j] != 0) { tempNode = malloc(sizeof(*tempNode)); tempNode->vertex = j; tempNode->link = NULL; // 현재 링크에 아무것도 없는 경우 if (!graph[i].link) { graph[i].link = tempNode; tempNode2 = tempNode; } else { tempNode2->link = tempNode; tempNode2 = tempNode; } graph[j].count++; } } } topSort(graph, vertexNum); return 0; }
/input.txt
6 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0

코드는 정확히 이해하지는 못햇으나 그냥

이런 식의 자료구조에서, indegree가 count인데, count가 0이라는 것은 predecessor가 없다는 뜻이고 이는 이제 이 vertex차례라는 것을 의미합니다. 그리고 0을 출력하고 없애면 이에 연결되어 있는 link vertex들에 해당하는 count를 그만큼 삭감 해주는 것이다. 그리고 또 0이 나오는 것이 있을 것이고 차례대로 또 위 과정을 반복하면 되는 것 같습니다.
AOE Network
AOE는 Activity On Edge의 약자로, 간선은 작업에 걸리는 시간을 가지고 있습니다. AOE 네트워크의 목표는 작업들을 수행하는 데 걸리는 최단시간을 구하는 것입니다.

위의 그래프에서 V0가 시작점, V7이 도착점을 나타내게 됩니다.
AOE는 헷갈리는 용어가 많습니다.
# 정점 i, j가 있고, <i, j>를 나타내는 간선 k가 있을 때
early[k]는 간선 k가 실행되기 위한 가장 빠른 시간을 나타냅니다.
earlist[k]는 정점 i가 일어날 수 있는 가장 빠른 시간을 나타내게 됩니다.
예를 들어, 위 그래프에서 V4를 봅시다. V0 -> V1 -> V4를 거쳐 오는 경로는 "10"의 시간이 걸리고, V0 -> V2 -> V4를 거쳐 오는 경로는 "9"의 시간이 걸리게 됩니다. V1, V2이 모두 완료되어야 V4이 시작될 수 있습니다. 따라서 V4를 시작하기 위해선 적어도 "10"의 시간이 걸립니다.
따라서 earlist[4] = early[6] = early[7] = 10이게 됩니다.
반대 개념이 존재하게 됩니다.
late[k]는 간선 k가 실행될 수 있는 가장 늦은 시간을 나타냅니다.
latest[j]는 정점 j가 일어날 수 있는 가장 늦은 시간을 나타내게 됩니다.
이번에도 위 그래프에서 V4를 봅시다. V7이 실행될 수 있는 가장 빠른 시간 ( = earlist[7] )은 "21"입니다. 맨 마지막이므로 V7이 실행될 수 있는 가장 늦은 시간 (=latest[7])도 "21"입니다. V4 -> V5 -> V7과정에서 "11"시간이 걸렸고, V4 -> V6 -> V7과정에서 "9"시간이 걸렸으므로 후자의 과정의 경우 전자 보다 "2"시간 늦게 작업을 시작해도 똑같이 끝낼 수 있습니다. 따라서 V4가 시작할 수 있는 가장 늦은 시간은 21 - 9 = "12"입니다.
Criticality라는 것도 있습니다. late[k] - early[k]를 나타내는 것인데, Criticality가 클수록 여유로운 놈이 됩니다. Criticality = 0인 작업을 Critical activity라고 하고, AOE네트워크의 목표는 작업들을 수행하는 데 걸리는 시간을 계산하는 것도 있지만, 그걸 통해 효율적으로 작업을 분배하기 위한 목적도 있습니다.
또한 critical path는 가장 긴 network path입니다.
예시

다음과 같은 AOE네트워크가 있다고 해 봅시다. 그럼 E0은 start of project가 되고, E4는 a1의 completion이 됩니다. ...
- critical path
- 0, 1, 4, 6, 8이 critical path가 되게 됩니다 (length = 18)
- earlist time
- E4가 일어날 수 있는 earlist time은 6 + 1인 7이 됩니다.
- earlist start time
- e(7) = e(8) = 7이 됩니다. earlist time이 7이기 때문입니다.
- latest time
- l(6) = 18 - 10 = 8, l(8) = 18 - 11 = 7
- critical activites
- e(8) = l(8) = 7
a5 -> e(5) = ee[2] = 4, l(5) = le(4) - duration of activity a5 = 7 - 1 = 6
a8 -> e(8) = ee(4) = 7, l(8) = le(7) - duration of activity a8 = 14 - 7 = 7
a8 is ctitical activity
'School > DataStructure' 카테고리의 다른 글
Data Structure - Sorting ( Quick Sort ) (0) | 2022.05.28 |
---|---|
Data Structure - Sorting ( Insertion Sort ) (0) | 2022.05.28 |
Data Structure - Graph ( Floyd-Warshall Algorithm && Transitive Closure ) (0) | 2022.05.27 |
Data Structure - Graph ( Dijkstra && Bellman and Ford Algorithm ) (0) | 2022.05.27 |
Data Structure - Graph ( MST ) (0) | 2022.05.27 |