拓扑排序实现:
//拓扑排序
stack<int >topOrder;
//拓扑排序,顺便求ve数组
bool topologicalSort(){
queue<int >q;
for(int i =0;i < n;i++){
if(inDegree[i] == 0)
{
q.push(i);
}
}
while(!q.empty()){
int u = q.front();
q.pop();
topOrder.push(u);
for(int i = 0;i < G[u].size();i++){
int v = G[u][i].v;
inDegree[v]--;
if(inDegree[v] == 0){
q.push(v);
}
//用ve[u]来更新u的所有后继结点v
if(ve[u] + G[u][i].w > ve[v]){
ve[v] = ve[u] + G[u][i].w;
}
}
}
if(topOrder.size() == n) return true;
else return false;
}
颠倒拓扑排序来得到一组合法的逆拓扑排序,由上面实现拓扑排序的过程中来使用了栈来存储拓扑序列,那么只需要按顺序出栈就是逆拓扑序列。
上述具体实现如下:
fill(vl,vl+n,ve[n-1]);
//直接使用topOrder出栈即为逆拓扑序列,求解vl数组
while(!topOrder.empty()){
int u = topOrder.top();
topOrder.pop();
for(int i = 0;i < G[u].size;i++){
int v = G[u][i].v;//u的后继结点v
if(vl[v] - G[u][i].w < vl[u]){
vl[u] = vl[v] - G[u][i].w;
}
}
}
关键路径
int CriticalPath(){
memset(ve,0,sizeof(ve));
if(topologicalSort() == false){
return -1;//不是有向无环图,返回-1
}
fill(vl,vl+n,ve[n -1]);
while(!topOrder.empty()){
int u = topOrder.top();
topOrder.pop();
for(int i = 0;i < G[u].size();i++){
int v = G[u][i].v;
//用u的所有后继结点v的vl值来更新vl[u]
if(vl[v] - G[u][i].w < vl[u]){
vl[u] = vl[v] - G[u][i].w;
}
}
}
//遍历邻接表的所有边,计算活动的最早开始时间e和最迟开始时间l
for(int u = 0;u < n;u++){
for(int i = 0;i < G[u].size();i++){
int v = G[u][i].v , w = G[u][i].w;
//活动的最早开始时间e和最迟开始时间l
int e = ve[u],l = vl[v] - w;
if(e == 1){
printf("%d ->%d\n",u,v);//输出关键活动
}
}
}
return ve[n -1];//返回关键路径长度
}
当要获得关键路径长度时,
int maxLength = 0;
for(int i =0 ;i < n;i++){
if(ve[i] > maxLength){
maxLength = ve[i];
}
}
fill(vl,vl + n,maxLength);