AOV网:在DAG中,用顶点表示活动,用弧表示活动之间的优先关系的有向图称为顶点表示活动的网---->工程中小项目次序
AOE网:在DAG中,用顶点表示事件,用带权有向边表示活动,边权表示活动持续时间
---->工程中小项目次序,每个小项目多久做完,整个工程多久做完
事件:刹那间发生的一件事情
活动:一个完整流程,可能由很多事件组成,有开始和结束
关键路径:整个项目工程中,耗时最长的路径称为关键路径,关键路径上的活动称为关键活动。---->注:关键路径不唯一,我们需要关注所有关键路径
关键路径:从起点到终点,最长的路径(们),由关键活动组成。
关键活动:最早开始时间 == 最晚开始时间 ETE == LTE
非关键活动:最早开始时间 != 最晚开始时间 ETE != LTE
(1)事件最早发生时间(ETV)
1.起点事件start最早发生时间 == 0 ETV[start] == 0
2.其余事件的最早发生时间基于拓扑序列去算
ETV[j] = max(ETV[j],ETV[i]+wi) i------>j
(2)事件最晚发生时间(LTV)
1.终点事件end的最晚发生时间 LTV[end] = ETV[end] (若未给出的话则按左式计算)
2.其余事件最晚发生时间基于逆拓扑序列计算
LTV[i] = min(LTV[i],LTV[j]-wj) i------>j
3.起点事件start最晚发生时间 == 0 LTV[start] == 0 == ETV[start]
(3)活动最早开始时间(ETE/ES)
1.ETE==该边起点事件的ETV
ETE = ETV[i]
(4)活动最晚开始时间(LTE/LS)
注:保证终点事件在DDL之前按时发生
1.LTE==该边终点事件LTV - 该边权值
注:终点事件最早发生时间就是工程完成时间
时间复杂度:O(n+m)
注:n为点数,m为边数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//引入一个栈,用于保存所有入度为零的的点的下标
class Stack_Node
{
public:
int data;
Stack_Node* next;
};
class m_stack
{
public:
Stack_Node* head;
public:
m_stack()
{
head = new Stack_Node;
if (head == nullptr)
{
cout << "开辟失败" << endl;
}
else
{
head->next = nullptr;
}
}
void m_push(int k)
{
Stack_Node* p = new Stack_Node;
p->data = k;
p->next = head->next;
head->next = p;
}
int m_pop()
{
if (head->next == nullptr)
{
cout << "栈空" << endl;
return -1;
}
Stack_Node* p = head->next;
int ret = p->data;
head->next = p->next;
delete p;
p = nullptr;
return ret;
}
};
class List_Node
{
public:
int data;
int wi;//权值
List_Node* next;
};
class Graph_Node
{
public:
char vi;
List_Node* first;
};
class Graph
{
public:
int size1;//点的个数
int size2;//边的个数
Graph_Node* g;//邻接表
int* ind;//入度数组
int* topo;//拓扑序列,改为记录下标便于计算
int* etv;//事件最早发生时间
int* ltv;//事件最晚发生时间
public:
Graph(int sz1,int sz2):size1(sz1),size2(sz2)
{
g = new Graph_Node[sz1];
ind = new int[sz1];
topo = new int[sz1];
etv = new int[sz1];
ltv = new int[sz1];
if (g == nullptr ||
ind == nullptr ||
topo == nullptr||
etv == nullptr ||
ltv == nullptr)
{
cout << "开辟失败" << endl;
}
else
{
//初始化点
for (int i = 0; i < sz1; ++i)
{
cin >> g[i].vi;
g[i].first = nullptr;
ind[i] = 0;
topo[i] = 0;
etv[i] = 0;
}
//输入边
char x(0);
char y(0);
int xi(0);
int yi(0);
int w(0);
for (int i = 0; i < sz2; ++i)
{
cin >> x >> y >> w;
xi = find(x);
yi = find(y);
//y为x邻接点
List_Node* s = new List_Node;
s->data = yi;
s->wi = w;
//进行头插
s->next = g[xi].first;
g[xi].first = s;
//统计y入度
ind[yi]++;
}
}
}
int find(char k)
{
for (int i = 0; i < size1; ++i)
{
if (g[i].vi == k)
{
return i;
}
}
return -1;
}
bool topo_sort()
{
bool flag(false);//判断能否找到拓扑序列
//引入一个栈,用于保存所有入度为零的的点的下标
m_stack s;
for (int i = 0; i < size1; ++i)
{
if (ind[i] == 0)
{
s.m_push(i);
}
}
int v_i(0);//出栈点的下标
//j为topo数组下标
for (int i = 0, j = 0; i < size1; ++i, ++j)
{
v_i = s.m_pop();
if (v_i == -1)
{
flag = false;//找不到拓扑序列
break;
}
//删除(并没有真正删除,只是入度减一)
topo[j] = v_i;
List_Node* p = g[v_i].first;
int a(0);//存储邻接点下标
while (p != nullptr) //v_i------>a
{
a = p->data;
ind[a]--;
//更新v_i邻接点etv
if (etv[a] < etv[v_i] + p->wi)
{
etv[a] = etv[v_i] + p->wi;
}
if (ind[a] == 0)
{
s.m_push(a);
}
p = p->next;
}
if (i == size1 - 1)
{
flag = true;
}
}
if (flag == false)
{
cout << "该图带环,无拓扑序列" << endl;
return flag;
}
else
{
cout << "该图拓扑序列为:" << endl;
for (int i = 0; i < size1; ++i)
{
cout << topo[i] << ' ';
}
cout << endl;
return flag;
}
}
void Critical_Path()
{
//end为结束事件下标
int end(topo[size1 - 1]);
//初始化ltv
for (int i = 0; i < size2; ++i)
{
ltv[i] = etv[end];
}
//基于逆拓扑序列更新ltv
//求x的ltv
int x(0);
for (int i = size1 - 2; i >= 0; --i)
{
x = topo[i];
//遍历x出边单链表
List_Node* p = g[x].first;
//存储邻接点下标
int a(0);
while (p != nullptr)
{
a = p->data; //x------->a
if (ltv[x] > ltv[a] - p->wi)
{
ltv[x] = ltv[a] - p->wi;
}
p = p->next;
}
}
cout << "以下是关键活动" << endl;
//遍历所有边,求每个边的ete,lte
//k为终点,i为起点
int k(0);
int ete(0);
int lte(0);
for (int i = 0; i < size1; ++i)
{
for (List_Node* p = g[i].first; p != nullptr; p = p->next)
{
k = p->data;
ete = etv[i];
lte = ltv[k] - p->wi;
if (ete == lte)
{
cout << g[i].vi << ' ' << g[k].vi << endl;
}
}
}
}
};
int main()
{
Graph g(9, 11);
g.topo_sort();
g.Critical_Path();
return 0;
}
/*
9 11
A B C D E F G H I
A B 6
A C 4
A D 5
B E 1
C E 1
D F 2
E G 9
E H 7
F H 4
G I 2
H I 4
*/