获取AOE网的关键路径
作者: 冯向阳
时间限制: 1s
章节: 课程设计
问题描述
建立一个有向网AOE网,设计并完成一算法Get_CriticalPath(),获取关键路径。该路径仅输出,不须保存。
提示:在AOE网中,
(1)关键活动:开始时间余量为0的活动。即活动的最早开始时间等于它的最迟开始时间。
(2)根据各个顶点的Ve和Vl值,在求得每条弧s的最早开始时间e[s]和最迟开始时间l[s]后,若某条弧满足条件e[s]=l[s],该弧所对应的活动即为关键活动。
(3)关键路径:由关键活动所形成的从源点到汇点的每一条路径(注意:关键路径可能有多条)。
参考函数原型:
//获取AOE网各顶点事件的最早发生时间ve和最迟发生时间vl、活动ak的最早开始时间e和最迟开始时间l、一条关键路径
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::Get_CriticalPath(int ve[], int vl[]);
输入说明
第一行:图的类型
第二行:结点数
第三行:结点集
第四行:边数
第五行:边集
第六行:权集
输出说明
第一行:顶点集
第二行:邻接表
空行
顶点i Ve[i] Vl[i](列与列之间用格式控制符'\t'分隔)
...
空行
<弧尾,弧头> e[k] l[k](列与列之间用格式控制符'\t'分隔)
...
空行
<弧尾,弧头>-><弧尾,弧头>...
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include<tuple>
using namespace std;
template<class TypeOfEdge>
struct edgeNode
{
int end;
TypeOfEdge weight;
edgeNode<TypeOfEdge>* next;
edgeNode(const int& e, const TypeOfEdge& w, edgeNode<TypeOfEdge>* ptr = nullptr)
{
end = e;
weight = w;
next = ptr;
}
};
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
TypeOfVer ver;
edgeNode<TypeOfEdge>* head;
verNode(edgeNode<TypeOfEdge>* h = nullptr)
{
head = h;
}
};
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph
{
private:
int Vers; // Number of vertices
int Edges; // Number of edges
verNode<TypeOfVer, TypeOfEdge>* verList;
string GraphKind;
public:
adjlist_graph(const string& kd, int vSize, const TypeOfVer d[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int i = 0; i < eSize; ++i)
{
int u = e[i][0];
int v = e[i][1];
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, 0, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, 0, verList[v].head);
verList[v].head = newNode;
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e, const TypeOfEdge w[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int k = 0; k < eSize; ++k)
{
int u = e[k][0];
int v = e[k][1];
TypeOfEdge weight = w[k];
if (GraphKind == "DG" || GraphKind == "DN")
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
}
else
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, weight, verList[v].head);
verList[v].head = newNode;
}
}
}
~adjlist_graph()
{
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
edgeNode<TypeOfEdge>* temp = curr;
curr = curr->next;
delete temp;
}
}
delete[] verList;
}
void printAdjList()
{
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
cout << "->" << curr->end << "(" << curr->weight << ")";
curr = curr->next;
}
cout << endl;
}
}
bool PrintMatrix()
{
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
if (i != Vers - 1)
cout << " ";
}
cout << endl;
return true;
}
bool Get_CriticalPath(int ve[], int vl[]);
void printVeVl(int ve[], int vl[])
{
std::vector<std::tuple<TypeOfVer, TypeOfVer, int, int>> edgeInfo; // Store (u, v, e[k], l[k])
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
int u = i; // Tail
int v = curr->end; // Head
int ek = ve[u];
int lk = vl[v] - curr->weight;
edgeInfo.emplace_back(verList[u].ver, verList[v].ver, ek, lk);
curr = curr->next;
}
}
for (const auto& edge : edgeInfo)
{
// 使用结构化绑定解构tuple
auto [u, v, ek, lk] = edge;
std::cout << "<" << u << ","<< v << ">"<<"\t"<< ek ;
cout<<"\t"<< lk << std::endl;
}
}
void insert(TypeOfVer x, TypeOfVer y, TypeOfEdge w);
bool topological_sort(vector<int>& topoOrder);
void printVertexVeVl(int ve[], int vl[]);
};
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::insert(TypeOfVer x, TypeOfVer y, TypeOfEdge w)
{
int u = -1, v = -1;
for (int i = 0; i < Vers; ++i)
{
if (verList[i].ver == x) u = i;
if (verList[i].ver == y) v = i;
}
if (u != -1 && v != -1)
{
verList[u].head = new edgeNode<TypeOfEdge>(v, w, verList[u].head);
++Edges;
}
}
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::topological_sort(std::vector<int>& topoOrder)
{
std::vector<int> inDegree(Vers, 0);
for (int i = 0; i < Vers; ++i)
{
for (edgeNode<TypeOfEdge>* p = verList[i].head; p != nullptr; p = p->next)
{
++inDegree[p->end];
}
}
std::queue<int> q;
for (int i = 0; i < Vers; ++i)
{
if (inDegree[i] == 0) q.push(i);
}
while (!q.empty())
{
int u = q.front();
q.pop();
topoOrder.push_back(u);
for (edgeNode<TypeOfEdge>* p = verList[u].head; p != nullptr; p = p->next)
{
if (--inDegree[p->end] == 0) q.push(p->end);
}
}
return (topoOrder.size() == Vers);
}
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::printVertexVeVl(int ve[], int vl[])
{
for (int i = 0; i < Vers; ++i)
{
std::cout << verList[i].ver << "\t" << ve[i] << "\t" << vl[i] << "\n";
}
}
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::Get_CriticalPath(int ve[], int vl[])
{
cout << endl;
std::vector<int> topoOrder;
if (!topological_sort(topoOrder)) return false;
// Step 2: Calculate ve[]
for (int i = 0; i < Vers; ++i) ve[i] = 0;
for (int i : topoOrder)
{
for (edgeNode<TypeOfEdge>* p = verList[i].head; p != nullptr; p = p->next)
{
if (ve[p->end] < ve[i] + p->weight) ve[p->end] = ve[i] + p->weight;
}
}
// Step 3: Calculate vl[]
for (int i = 0; i < Vers; ++i) vl[i] = ve[Vers - 1];
for (auto it = topoOrder.rbegin(); it != topoOrder.rend(); ++it)
{
int i = *it;
for (edgeNode<TypeOfEdge>* p = verList[i].head; p != nullptr; p = p->next)
{
if (vl[i] > vl[p->end] - p->weight) vl[i] = vl[p->end] - p->weight;
}
}
// Print ve and vl
printVertexVeVl(ve, vl);
cout << endl;
printVeVl(ve, vl);
cout << endl;
// Step 4: Identify and print the critical path
std::vector<std::pair<TypeOfVer, TypeOfVer>> path;
for (int i = 0; i < Vers; ++i)
{
for (edgeNode<TypeOfEdge>* p = verList[i].head; p != nullptr; p = p->next)
{
int e = ve[i];
int l = vl[p->end] - p->weight;
if (e == l)
{
path.emplace_back(verList[i].ver, verList[p->end].ver);
}
}
}
// Print the critical path
for (size_t i = 0; i < path.size(); ++i)
{
std::cout << "(" << path[i].first << "," << path[i].second << ")";
if (i != path.size() - 1)
{
cout << "->";
}
}
std::cout << std::endl;
return true;
}
int main()
{
string graphType;
int n, m;
cin >> graphType >> n;
char* verArr = new char[n];
for (int i = 0; i < n; ++i)
{
cin >> verArr[i];
}
cin >> m;
int** edgeArr = new int* [m];
for (int i = 0; i < m; ++i)
{
edgeArr[i] = new int[2];
cin >> edgeArr[i][0] >> edgeArr[i][1];
}
int* weightArr = new int[m];
for (int i = 0; i < m; ++i)
{
cin >> weightArr[i];
}
adjlist_graph<char, int> graph(graphType, n, m, verArr, edgeArr, weightArr);
graph.PrintMatrix();
graph.printAdjList();
int* ve = new int[n];
int* vl = new int[n];
graph.Get_CriticalPath(ve, vl);
return 0;
}