偏序: (a、b、c代表顶点,R代表关系,aRb表示a到b有路径存在)
1.自反的—对于每一个顶点都有aRa(忽略)
2.反对称的—对于任意两个顶点a、b,aRb和bRa不能同时存在,即a到b有路径,b到a就不能有路径
3.传递的—aRb、bRc则,必有aRc 全序:任取两个顶点,a、b,必有aRb或bRa的偏序,即对于任两个顶点都有先后关系的偏序
拓扑排序:图是偏序的,由此输出的排序是全序的(AOV,顶点表示活动,弧表示优先关系的有向图)
方法:任取入度为0的点输出,然后去掉这个点,与这个点关联的点入度-1,循环直至所有点输出(成功),或者出现环结束(失败)
AOE网:弧表示活动,顶点表示事件,权表示活动持续时间
关键路径:路径最长的那段路径叫关键路径
4个辅助:(e(i-j)==l(i-j)为关键路径)
ve(i)事件i的最早发生时间
vl(i)事件i的最迟发生时间
e(i-j)活动最早发生时间(明显等于e(i))
l(i-j) 活动最晚发生时间(明显等于l(j)-dut<I,j>
)
显然:
ve(j)=max{ve(i)+dut<I,j>}
vl(i)=min{vl(j)-dut<I,j>}
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int N, M;
struct ArcNode {//弧节点
int ft;
int tim;
int nt;
ArcNode *next;
ArcNode() { next = NULL; }
};
struct VNode {//顶点节点
string data;
ArcNode *first;
VNode() { first = NULL; }
};
struct Graph {
vector<VNode> V;//顶点
vector<ArcNode> A;//弧节点
vector<int> Indegree;//入度
vector<int> ve;//事件最早发生时间
vector<int> vl;//事件最晚发生时间
};
Graph G;
int find_index(string a)//顶点名称对应的顶点位置
{
for (int t = 0;t < N;t++)
if (G.V[t].data == a) return t;
cout << "ERROR" << endl;
exit(0);
return -1;
}
void CreateGraph(Graph &G)
{
cout << "请输入顶点个数" << endl;
cin >> N;
cout << "请输入弧的数量" << endl;
cin >> M;
G.A.resize(M);G.V.resize(N);
cout << "请依次输入顶点的名称,名称之间用空格隔开" << endl;
for (int t = 0;t < N;t++)
cin >> G.V[t].data;
cout << "请依次输入弧的尾顶点 头顶点 弧长" << endl;
vector<ArcNode *> temp(N, NULL);//指向每个顶点的末尾
G.Indegree.resize(N);
for (int t = 0;t <M;t++)//用邻接表结构创建图
{
string a, b;
int t_a, t_b, c;
cin >> a >> b >> c;
G.A[t].tim = c;
t_a = find_index(a);
t_b = find_index(b);
G.A[t].ft = t_a;
G.A[t].nt = t_b;
G.Indegree[t_b]++;
if (G.V[t_a].first == NULL)
temp[t_a] = G.V[t_a].first = &G.A[t];
else
temp[t_a] = temp[t_a]->next = &G.A[t];
}
}
void Print_G(Graph &G)//中途检查用,忽略
{
for (auto x : G.V)
{
cout << x.data << endl;
ArcNode *p = x.first;
while (p != NULL)
{
cout << p->nt << " ";
p = p->next;
}
cout << endl;
}
}
vector<int> Topu;//保存拓扑排序
bool TopuSort(Graph &G)//拓扑排序+关键路径求ve[i]
{
G.ve.resize(N);
vector<int> temp_Indegree(G.Indegree);
vector<int> temp;//过程中使用的栈
for (int t = 0;t < N;t++)
if (temp_Indegree[t] == 0) temp.push_back(t);
while (!temp.empty())
{
Topu.push_back(temp.back());//输出到栈Topu中
int j = temp.back();
ArcNode *p = G.V[j].first;temp.pop_back();
while (p != NULL)
{
if (--temp_Indegree[p->nt] == 0) temp.push_back(p->nt);
if (G.ve[j] + p->tim>G.ve[p->nt]) G.ve[p->nt] = G.ve[j] + p->tim;//求ve[i]
p = p->next;
}
}
if (Topu.size() != G.V.size()) return false;
return true;
}
bool CriticalPath(Graph &G)//计算vl[i],并输出最短路径
{
if (!TopuSort(G)) return false;
G.vl.assign(N, G.ve.back());
while (!Topu.empty())//计算vl[i]
{
int j = Topu.back();
ArcNode *p = G.V[j].first;Topu.pop_back();
while (p != NULL)
{
if (G.vl[p->nt] - p->tim < G.vl[j])G.vl[j] = G.vl[p->nt] - p->tim;
p = p->next;
}
}
for (int t = 0;t < M;t++)//输出
{
int e = G.ve[G.A[t].ft], l = G.vl[G.A[t].nt]-G.A[t].tim;
if (e == l) printf("关键路径:%s %s,花费时间%d\n", G.V[G.A[t].ft].data.c_str(), G.V[G.A[t].nt].data.c_str(), G.A[t].tim);
}
}
int main()
{
CreateGraph(G);
CriticalPath(G);
}