AOE-網如下:
把圖中的AOE-網看作一個工程的話,則就需要解決下面兩個問題:
- 估算完成整項工程至少需要多少時間
- 判斷哪些活動是影響工程進度的關鍵
分析
整個工程只有一個開始點和一個完成點,所以在正常的情況(無環)下,網中只有一個入度爲零的點,稱爲源點,也只有一個出度爲零的點,稱爲匯點。在整個AOE-網中,一條路徑各弧上的權值之和稱爲該路徑的帶權路徑長度。要估算整項工程完成的最短時間,就是要找一條從源點到匯點的帶權路徑最長的路徑,稱爲關鍵路徑。關鍵路徑上的活動叫做關鍵活動,這些活動是影響工程進度的關鍵,他們提前或拖延將使整個工程提前或拖延。
確定關鍵路徑
一,定義4個描述量
1,事件N的最早發生時間ve[N的下標]
進入事件N的每一活動都結束,N才能發生,所以ve[N的下標]是從源點到N的最長路徑長度
2,事件N的最遲發生時間vl[N的下標]
事件N的發生不得延遲於N的每一後繼事件的最遲發生時間。
爲了不拖延工期,N的最遲發生時間不得遲於其後繼事件M的最遲發生事件減去N到M的持續時間
eg:若N是B,M是E;則N的最遲發生時間不得遲於M的最遲發生時間減去MN之間的時間1.
3,活動的最早開始時間e[]
只有事件N發生了,活動x才能發生,所以,活動x的最早開始時間等於事件N的最早發生事件ve[N的下標]
eg:若N是B,x是代表BE這條弧,則只有事件B發生了,活動BE才能發生
4,活動的最晚開始時間l[]
活動x的開始事件需保證不延誤事件N的最遲發生時間。所以,活動x的最晚開始時間等於事件N的最遲發生時間vl[N的下標]減去活動x持續的時間
eg:若N是E,x是代表BE這條弧,則BE不能厭惡N的發生,所以最晚開始時間等於vl[N]-BE;
二,關鍵路徑求解過程
- 對圖中頂點進行排序,在排序過程中按照拓撲序列求出每個事件的最早發生時間ve[];
- 按照逆拓撲排序求出每個事件的最遲發生時間vl[];
- 求出每個活動XY的最早開始時間e[];
- 求出每個活動XV的最晚開始時間l[];
- 如果e[i]=l[i],即爲關鍵活動。由關鍵活動形成的由源點到匯點的每一條路徑就是關鍵路徑,關鍵路徑可能不止一條
三,關鍵路徑部分求解代碼
int ve[pointMax]; //最早發生時間
int vl[pointMax]; //最晚發生時間
void CritPath(ATgroup *A)
{
int n = A->point; //n爲頂點個數
for (int i = 0; i < n; i++) //將每個事件的最早事件爲0
ve[i] = 0;
//---按拓撲次序求每個事件的最早發生時間---//
int k, j;
for (int i = 0; i < n; i++)
{
k = topo[i]; //取的拓撲排序中的頂點序號
cout <<"K=F"<< k << " "<<endl;
VtNode *p = A->vertices[k].Out; //指向K的第一個鄰接結點
while (p != NULL)
{
j = p->peaceE;
if (ve[j] < ve[k] + p->len)
{
ve[j] = ve[k] + p->len;
cout << ve[j] << " " << ve[k] << " " << p->len << endl;
}
p = p->nextVtt;
}
cout << ve[j] << endl;
}
for (int i = 0; i < A->point; i++)
{
cout << ve[i] << " ";
}
cout << endl;
cout << endl;
for (int i = 0; i < n; i++) //初始化
{
vl[i] = ve[topo[n - 1]];
}
//---按逆拓撲排序求每個事件的最遲發生時間----//
for (int i = n - 1; i >= 0; i--)
{
k = topo[i]; //取的拓撲排序中的頂點序號
VtNode *p = A->vertices[k].Out; //指向K的第一個鄰接結點
//cout << k << endl;
while (p != NULL)
{
j = p->peaceE;
if (vl[k] > vl[j] - p->len)
{
vl[k] = vl[j] - p->len;
//cout << vl[k] << " " << vl[j] << " " << p->len << endl;
}
p = p->nextVtt;
}
//cout << vl[j] << endl;
}
for (int i = 0; i < A->point; i++)
{
cout << vl[i] << " ";
}
cout << endl;
cout << endl;
//----判斷每一活動是否爲關鍵活動-----//
int e, l;
for (int i = 0; i < n; i++)
{
VtNode *p = A->vertices[i].Out;
while (p != NULL)
{
j = p->peaceE;
e = ve[i];
l = vl[j] - p->len;
if (e == l)
{
cout << A->vertices[i].data << " " << A->vertices[j].data << endl;
}
p = p->nextVtt;
}
}
}
四,整段程序代碼
#include<iostream>
using namespace std;
#define pointMax 100
struct VtNode //權值信息
{
VtNode *nextVt; //入度鏈表下一個結點
int peace; //入度下一頂點的值
VtNode *nextVtt; //出度鏈表下一個結點
int peaceE; //出度下一頂點的值
int len;
};
struct PoNode //頂點信息
{
char data;
VtNode *firstPo; //入度
VtNode *Out; //出度
};
struct ATgroup
{
PoNode vertices[pointMax]; //每一個verticse代表一個頂點
int point, vert; //point頂點數,vert弧數
};
struct Node
{
int data;
Node *next;
};
struct SqStack //棧
{
Node *base; //棧底
Node *top; //棧頂
int data;
};
void Push(SqStack &S, int i) //入棧
{
Node *m = new Node;
m->data = i;
m->next = S.top; //入棧過程
S.top = m;
}
int Pop(SqStack &S) //出棧
{
int n = S.top->data;
S.top = S.top->next; //出棧過程
return n;
}
int ATlocate(ATgroup A, char x) //找到位置
{
for (int i = 0; i < A.point; i++) //依次遍歷點的信息
{
if (A.vertices[i].data == x) //找到x的位置
{
return i;
}
}
}
void show(ATgroup &A) //顯示當前所有點入度出度的頂點
{
//cout << endl;
for (int i = 0; i < A.point; i++)
{
//cout << i;
if (A.vertices[i].firstPo != NULL) //入度位置
{
// cout << " " << A.vertices[i].firstPo->peace << " ";
}
//else
// cout << " -1" << " ";
if (A.vertices[i].Out != NULL) //出度位置
{
// cout << A.vertices[i].Out->peaceE << endl;
}
//else
// cout << " -1" << endl;
}
}
void CreatAT(ATgroup &A)
{
cout << "輸入鄰接矩陣頂點數:";
cin >> A.point;
cout << "輸入鄰接矩陣邊數:";
cin >> A.vert;
getchar();
char q[100];
cout << "輸入頂點信息:";
gets_s(q);
for (int i = 0; i < A.point; i++)
{
A.vertices[i].data = q[i]; //輸入頂點值
A.vertices[i].firstPo = NULL; //初始化頭結點爲空
A.vertices[i].Out = NULL;
}
char v1, v2; int m, n; int len;
for (int i = 0; i < A.vert; i++) //輸入各邊,構造鄰接表
{
cout << "輸入第" << i << "條邊的依附的兩個頂點:";
int Q;
cin >> v1 >> v2 >> Q;
m = ATlocate(A, v1); //確定位置
n = ATlocate(A, v2);
//第一個
VtNode *p1 = new VtNode;
VtNode *p2 = new VtNode;
p1->peace = m; //入度
p1->nextVt = A.vertices[n].firstPo;
A.vertices[n].firstPo = p1;
p2->peaceE = n; //出度
p2->nextVtt = A.vertices[m].Out;
p2->len = Q;
A.vertices[m].Out = p2;
}
//show(A);
}
void FindIn(ATgroup *A, int *in) //統計所有點的入度數並存入到in數組中
{
int n = 0;
for (int i = 0; i < A->point; i++) //遍歷每一個點
{
VtNode *p = new VtNode;
p = A->vertices[i].firstPo;
while (p != NULL) //將入度鏈表進行遍歷
{
n++;
p = p->nextVt; //下一結點
}
in[i] = n; //存入in數組
n = 0;
}
}
void SHOW(int *a, ATgroup *A) //顯示當前所有頂點入度數量還有幾個
{
for (int i = 0; i < A->point; i++)
{
//cout << a[i] << " ";
}
//cout << endl;
}
int M[pointMax] = { 0 };
int topo[pointMax]; //拓撲遍歷存入
void TPsort(ATgroup *A, SqStack &S) //拓撲排序過程
{
int Indegree[pointMax];
FindIn(A, Indegree); //將入度賦值給數組
for (int i = 0; i < A->point; i++)
{
if (Indegree[i] == 0) //將所有入度等於0的入棧
{
//cout << "Push=" << i << endl;
Push(S, i);
}
}
int m = 0; //統計入度的頂點數
int n, k;
while (S.base != S.top) //判斷是否遍歷完
{
//cout << endl;
n = Pop(S); //棧頂出棧
//cout << "Pop=" << n << endl;
topo[m] = n; //存入topo
m++;
VtNode* p = new VtNode;
p = A->vertices[n].Out; //出度鏈表的結點
while (p != NULL) //遍歷出度鏈表
{
k = p->peaceE; //某結點的位置
//cout << "出度下一結點k=" << k << endl;
Indegree[k]--; //將該結點頂點位置入度減一
//SHOW(Indegree, A); //顯示當前所有點的入度
if (Indegree[k] == 0) //當等於0時,入棧
{
//cout << "Push=" << k << endl;
Push(S, k);
}
p = p->nextVtt; //下一個
}
}
}
int ve[pointMax]; //最早發生時間
int vl[pointMax]; //最晚發生時間
void CritPath(ATgroup *A)
{
int n = A->point; //n爲頂點個數
for (int i = 0; i < n; i++) //將每個事件的最早事件爲0
ve[i] = 0;
//---按拓撲次序求每個事件的最早發生時間---//
int k, j;
for (int i = 0; i < n; i++)
{
k = topo[i]; //取的拓撲排序中的頂點序號
cout <<"K=F"<< k << " "<<endl;
VtNode *p = A->vertices[k].Out; //指向K的第一個鄰接結點
while (p != NULL)
{
j = p->peaceE;
if (ve[j] < ve[k] + p->len)
{
ve[j] = ve[k] + p->len;
cout << ve[j] << " " << ve[k] << " " << p->len << endl;
}
p = p->nextVtt;
}
cout << ve[j] << endl;
}
for (int i = 0; i < A->point; i++)
{
cout << ve[i] << " ";
}
cout << endl;
cout << endl;
for (int i = 0; i < n; i++) //初始化
{
vl[i] = ve[topo[n - 1]];
}
//---按逆拓撲排序求每個事件的最遲發生時間----//
for (int i = n - 1; i >= 0; i--)
{
k = topo[i]; //取的拓撲排序中的頂點序號
VtNode *p = A->vertices[k].Out; //指向K的第一個鄰接結點
//cout << k << endl;
while (p != NULL)
{
j = p->peaceE;
if (vl[k] > vl[j] - p->len)
{
vl[k] = vl[j] - p->len;
//cout << vl[k] << " " << vl[j] << " " << p->len << endl;
}
p = p->nextVtt;
}
//cout << vl[j] << endl;
}
for (int i = 0; i < A->point; i++)
{
cout << vl[i] << " ";
}
cout << endl;
cout << endl;
//----判斷每一活動是否爲關鍵活動-----//
int e, l;
for (int i = 0; i < n; i++)
{
VtNode *p = A->vertices[i].Out;
while (p != NULL)
{
j = p->peaceE;
e = ve[i];
l = vl[j] - p->len;
if (e == l)
{
cout << A->vertices[i].data << " " << A->vertices[j].data << endl;
}
p = p->nextVtt;
}
}
}
int main()
{
ATgroup *A = new ATgroup;
SqStack *S = new SqStack;
S->top = S->base;
S->data = pointMax;
CreatAT(*A);
TPsort(A, *S);
CritPath(A);
system("pause");
}