该路劲的求法主要是基于拓扑排序实现的
其中有4个数组
ve : 事件的最早发生时间
vl : 事件的最迟发生时间
ee : 活动的最早发生时间
el : 活动的最迟发生时间
其中 :
ve [i] 的值是所有值到当前节点的最大值
vl [i] 的值是逆拓扑排序的求最小值
ee: 是与他相连接的节点的最早发生时间
el 比如 x-y 表示的是用 用y的最迟发生时间 - 权值得到x最迟发生时间
然后比较ee == el
老习惯 看代码后边的注释
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#define MAX 100
using namespace std;
struct node{
int v; //和当前节点邻接的节点
int w; //边上的权值
};
vector<node> map[MAX]; // 保持邻接矩阵
int vex,edg; //表示节点总数 和 边的总数
int inDegree[MAX],ve[MAX],vl[MAX]; //分别表示入度函数 , 事件的最早发生时间 ,事件的最迟发生时间
stack<int > tuopo; //拓扑排序的保存栈
vector<node> imppath[MAX]; //关键路径的保存
vector<int> temp; //关键路径节点的输出 保存容器
void tp(){
int pos ; // pos = -1;
queue<int > q; //利用队列遍历拓扑排序
for (int i = 0; i < vex; ++i) {
if (inDegree[i]==0){ //所有入度为0的节点入队
q.push(i);
}
}
while (!q.empty()){ //队不为空则
pos=q.front();
q.pop();
tuopo.push(pos);
for (int i = 0; i < map[pos].size(); ++i) {
inDegree[map[pos][i].v]--;
if (inDegree[map[pos][i].v]==0){
q.push(map[pos][i].v);
}//以上都是正常的拓扑排序,map[pos][i].v表示pos的邻接点
if (ve[map[pos][i].v]<ve[pos]+map[pos][i].w){ //计算事件的最早发生时间
ve[map[pos][i].v]=ve[pos]+map[pos][i].w;//取最大值
}
}
}
}
int importantpath(){
int max=-1;
int end=0;
for (int i = 0; i < vex; ++i) { //找到汇点
if (ve[i]>max){
max=ve[i]; //记录最大时间
end=i; //记录终点
}
}
cout<<"lenth:"<<max<<endl; //输出最大时间
fill(vl,vl+vex,max); //初始化vl 因为是逆拓扑序列 所以都设为最大
while (!tuopo.empty()){ //逆拓扑排序开始
int pos= tuopo.top();
tuopo.pop();
for (int i = 0; i < map[pos].size(); ++i) { //用它邻接的点 来求它的事件的最迟发生时间
int v=map[pos][i].v;
if (vl[v]-map[pos][i].w<vl[pos]) //求最小值
vl[pos]=vl[v]-map[pos][i].w;
}
}
for (int i = 0; i < vex; ++i) { //进行ee el 的判断
for (int j = 0; j < map[i].size(); ++j) {
int v=map[i][j].v; //拿到当前邻接点
int w=map[i][j].w; //拿到权值
int e = ve[i]; //活动最早发生时间 就是ve[i] 是它前面出发点的最早发生时间=当前活动的最早发生事件
int l = vl[v]-w; //用 v的最迟发生时间-权值就是活动的最迟发生时间
if (e==l){
cout<<i<<" "<<v<<endl;
imppath[i].push_back({v,w});
}
}
}
return end;
}
void dfs(int start , int end ) { //dfs的遍历
temp.push_back(start);
if (start == end) {
for (int i = 0; i < temp.size() - 1; ++i) {
cout << temp[i] << " ";
}
cout << temp[temp.size() - 1] << endl;
return;
}
for (int i = 0; i < imppath[start].size(); ++i) {
int v=imppath[start][i].v;
dfs(v,end);
temp.pop_back();
}
}
int main(){
cout<<"请输入节点数和边数"<<endl;
cin>>vex>>edg;
cout<<"请输入边的起点和终点以及权值"<<endl;
for (int i = 0; i < edg; ++i) {
int x,y,w;
cin>>x>>y>>w;
map[x].push_back({y,w});
inDegree[y]++; //入度+1
}
tp();//拓扑排序
cout<<"关键活动"<<endl;
int end =importantpath();
cout<<"关键路径"<<endl;
dfs(0,end);
return 0;
}
测试样例
请输入节点数和边数
9 11
请输入边的起点和终点以及权值
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
关键活动
lenth:18
0 1
1 4
4 6
4 7
6 8
7 8
关键路径
0 1 4 6 8
0 1 4 7 8
特别提醒 :在AVE中 结点表示事件 边表示活动
所以区分清除:
ve : 事件的最早发生时间
vl : 事件的最迟发生时间ee : 活动的最早发生时间
el : 活动的最迟发生时间
是至关重要的!!