AOE网,带权有向图,边表示活动,顶点表示事件,既有活动之间的先后制约关系,又有活动的消耗,从源点到汇点的带权路径长度最大的路径称为关键路径,其中的活动称为关键活动。
#include<iostream>
#include<stack>
using namespace std;
const int maxNum = 100;
typedef struct arcNode { //弧结点类型
int tail; //弧尾下标
int head; //弧头下标
struct arcNode*hlink; //指针,指向同弧头的弧
struct arcNode*tlink; //指针,指向同弧尾的弧
int w;
}arcNode;
typedef struct vexNode
{
char data; //指点数据
arcNode *firstIn; //指针,指向第一个入弧
arcNode *firstout; //指针,指向第一个出弧
};
typedef struct {
vexNode vexs[maxNum];
int vexnum, edgenum; //顶点数量,边数量
}OLGraph;
OLGraph g;
int topo[maxNum];
int LocateVex(char c)
{
for (int i = 0; i < g.vexnum; i++)
{
if (g.vexs[i].data == c)
{
return i;
}
}
return -1;
}
void insertedge(char a, char b,int w)
{
int ai = LocateVex(a);
int bi = LocateVex(b);
arcNode* an = new arcNode; //生成一条新弧
an->tlink = g.vexs[ai].firstout; //顶点第一个出弧更新,尾插入
an->head = bi; //由ai->bi
an->tail = ai;
an->w = w; //ai->bi的权重
g.vexs[ai].firstout = an; //顶点第一个出弧更新,尾插入
an->hlink = NULL;
if (g.vexs[bi].firstIn == NULL)
{
g.vexs[bi].firstIn = an;
}
else
{
arcNode* curArc = g.vexs[bi].firstIn; //找到最后一个入弧
while (curArc->hlink != NULL)
{
curArc = curArc->hlink;
}
curArc->hlink = an;
}
}
void CreateOLGraph() {
cout << "请输入顶点数量和边数:" << endl;
cin >> g.vexnum >> g.edgenum;
cout << "输入对应的顶点:" << endl;
for (int i = 0; i < g.vexnum; i++)
{
cin >> g.vexs[i].data;
g.vexs[i].firstIn = NULL;
g.vexs[i].firstout = NULL;
}
cout << "输入要插入的边" << endl;
int m = g.edgenum;
while (m > 0)
{
char a, b;
int w;
cin >> a >> b>>w;
insertedge(a, b,w);
m--;
}
}
bool TopologicalSort()
{
int* indegree = new int[g.vexnum]; //入度数组
int k = 0;
stack<int> stack;
arcNode* an;
//初始化入度数组
for (int i = 0; i < g.vexnum; i++)
{
int m = 0;
an = g.vexs[i].firstIn;
while (an != NULL)
{
m++;
an = an->hlink;
}
indegree[i] = m;
}
//将入度为0的顶点索引加入栈中,当栈为空结束
for (int i = 0; i < g.vexnum; i++)
{
if (indegree[i] == 0)
stack.push(i);
}
while (stack.size() > 0)
{
int t = stack.top();
stack.pop();
topo[k] = t;
//把t顶点的所有出度的顶点入度全部减一
an = g.vexs[t].firstout;
while (an != NULL)
{
indegree[an->head]--;
if (indegree[an->head] == 0)
{
stack.push(an->head);
}
an = an->tlink;
}
k++;
}
if (k < g.vexnum)
return false;
else return true;
}
void CriticalPath()
{
int* ve = new int[g.vexnum]; //顶点最早开始时间
int* vl = new int[g.vexnum]; //顶点最迟开始时间
arcNode* an; //弧
if (!TopologicalSort())
{
cout << "该图有环,无拓扑排序!" << endl;
return;
}
//初始化各顶点最早开始时间为0
for (int i = 0; i < g.vexnum; i++)
{
ve[i] = 0;
}
//获取各顶点最早开始时间,拓扑排序从前往后
for (int i = 0; i < g.vexnum; i++)
{
an = g.vexs[topo[i]].firstout;
while (an != NULL)
{
if (ve[an->head] < ve[topo[i]] + an->w)
ve[an->head] = ve[topo[i]] + an->w;
an = an->tlink;
}
}
//初始化各顶点最迟开始时间
for (int i = g.vexnum-1; i >=0; i--)
{
vl[i] = ve[g.vexnum - 1];
}
//获取各顶点最迟开始时间,拓扑排序从后往前
for (int i = g.vexnum-1; i >=0 ; i--)
{
an = g.vexs[topo[i]].firstout;
while (an != NULL)
{
if (vl[topo[i]] > vl[an->head] - an->w)
vl[topo[i]] = vl[an->head] - an->w;
an = an->tlink;
}
}
//计算活动的最早和最迟,最早=最迟就是关键活动路径,拓扑排序从前往后
cout << "关键活动路径为:" << endl;
for (int i = 0; i < g.vexnum; i++)
{
int e, l;
an = g.vexs[topo[i]].firstout;
while (an != NULL)
{
e = ve[topo[i]];
l = vl[an->head] - an->w;
if (e == l)
{
cout <<"<"<< topo[i] << "," << an->head << "> ";
break;
}
an = an->tlink;
}
}
}
int main()
{
CreateOLGraph();
CriticalPath();
return 0;
}
测试用例
6 8
0 1 2 3 4 5
0 1 2
0 2 15
1 3 10
1 4 19
2 1 4
2 5 11
3 5 6
4 5 5