如果说拓扑排序是为了找到有向无环图AOV(动态顶点)的发生流程,关键路径则是AOE(动态边Active On Edge)有向无环图中 下一个事件(顶点)最早发生的时间,也就是现实生活中的一个老鼠坏一锅汤中的那只臭老鼠,一个故事,皇帝需要一味药来治病,各种药引子都准备好了,最重要的则是龙须一定要搞到~~(不太恰当)
有时候我们不能过度自信。。。。
可能很多人都遇到过一种情况,咦,怎么回事,明明正确(当然,是你觉得正确),怎么结果就是不对,可能只是某处的一个小细节导致,在很多情况下,怕我们都把这种错误归于,卧槽,有毒!!,总之我没错,肯定是这个程序有毒!!,我们不愿意承认程序有毒其实就是程序某个地方有漏洞!
今天遇见这个问题了,一切本来顺利,就是某个细节不对,像这样..
其实运行结果差的有点远了,关键路径经过的顶点那里不对,只不过后来在原来程序基础上面加了点东西,可能我就认为成功了,但如果就此结束的话,真的就。。。。太。。
是这样的,问题其实出在了栈的初始化上面,可能上一节也写错了,但是运行时候没有显示出错误,等下改掉;这都是总结吧
讲一下关键路径
关键路径指的是完成一项工程中,对这件工程时间起决定作用的事件
借助拓扑排序得到的序列和四个辅助数组
我们假设有路径<j,k>:
ve[]:最早发生事件,也就是最早什么时间到达某个顶点
ve[k]=ve[j]+k的权重
vl[]:最晚发生事件//初始所有vl等于ve中最大值
vl[j]=vl[k]-k的权重
ee[]:最早发生活动
ee[]=ve[j]
el[]:最晚发生活动 el=vl[k]-k权重
要注意的是,这里输入的顺序不同的话,构造出来的邻接图也不同,得到的拓扑序列也不一样。
但是关键路径是一样的。
#include <iostream>
#include <malloc.h>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX_SIZE 10
#define increase 10
typedef bool status;
typedef struct link
{
int data;//下标
int weiget;//权重
struct link* next;
}*enode;//表结点
typedef struct head_node
{
char data;
struct link* next;
}Head,*head;//头节点
typedef struct graph
{
int vexnum,arcnum;
Head vex[MAX_SIZE];
}*Graph;
struct my_stack
{
int *base;
int *top;
int stack_size;
};
int ve[MAX_SIZE];//时间最早发生时间
my_stack T;
//获取位置
int get_pos(Graph pit,char c)
{
for(int i=0;i<pit->vexnum;i++)
{
if(c==pit->vex[i].data)
{
return i;
}
}
return -1;
}
void link_last(enode &father,enode son)
{
while(father->next)
father=father->next;
father->next=son;
}
//创建邻接图
Graph creat_graph()
{
int vexnum,arcnum;
char in1,in2;
int weiget;
int p1,p2;
Graph pit=(Graph)malloc(sizeof(graph));
cout<<"请输入顶点数和边数:"<<endl;
cin>>vexnum>>arcnum;
pit->arcnum=arcnum;
pit->vexnum=vexnum;
cout<<"请输入所有顶点"<<endl;
for(int i=0;i<vexnum;i++)
{
cin>>pit->vex[i].data;
pit->vex[i].next=NULL;
}
for(int j=0;j<arcnum;j++)
{
cout<<"请输入弧边和权重"<<j+1<<endl;
cin>>in1>>in2>>weiget;
p1=get_pos(pit,in1);
p2=get_pos(pit,in2);
enode my_side=(enode)malloc(sizeof(link));
if(!my_side)cout<<"节点分配错误!!";
my_side->data=p2;
my_side->weiget=weiget;
my_side->next=NULL;
//把新的表结点连上去
if(pit->vex[p1].next==NULL)
pit->vex[p1].next=my_side;
else
link_last(pit->vex[p1].next,my_side);
}
return pit;
}
status isempty(my_stack &S)//判断是否为空,空的话返回true
{
if(S.base==S.top)return true;
else return false;
}
void stack_init(my_stack &S)//栈初始化
{
S.base=(int*)malloc(MAX_SIZE*sizeof(int));
if(!S.base)cout<<"分配栈出错"<<endl;
S.top=S.base;
S.stack_size=MAX_SIZE;
}
void stack_push(my_stack &S,int e)
{
if((S.top-S.base)==S.stack_size)//
{
S.base=(int *)realloc(S.base,(increase+S.stack_size)*sizeof(int));
if(!S.base)cout<<"栈重新分配错误!!"<<endl;
S.top=S.base+S.stack_size;
S.stack_size+=increase;
}
*(S.top)=e;
(S.top)++;
}
void stack_pop(my_stack &S,int &e)
{
if(S.base==S.top)cout<<"pop Error!!"<<endl;
e=*(--S.top);
}
void find_indegree(Graph pit,int *indegree)
{
enode p;
for(int i=0;i<pit->vexnum;i++)//入度初始化为零
{
indegree[i]=0;
}
for(int j=0;j<pit->vexnum;j++)
{
p=pit->vex[j].next;
while(p)//指针非空
{
indegree[p->data]++;
p=p->next;
}
}
}
/*
利用一个一维数组和栈
寻找入度等于零的
*/
status topology(Graph pit,my_stack &T)//拓扑排序
{
int indegree[MAX_SIZE];//入度数组
int num=0;
int e,k;
my_stack S;
enode p;
find_indegree(pit,indegree);//初始化入度
stack_init(S);//初始化栈
memset(ve,0,sizeof(ve));//事件最早发生时间初始化0,寻找最大值放进去
for(int i=0;i<pit->vexnum;i++)
{
if(!indegree[i])//如果入度等于零,入栈
{
stack_push(S,i);
}
}
while(!isempty(S))//如果非空
{
stack_pop(S,e);
cout<<pit->vex[e].data<<" ";
num++;//每输出一次,记录一下
stack_push(T,e);
for(p=pit->vex[e].next;p;p=p->next)
{
k=p->data;
if(!(--indegree[k]))//入度减一,若为0,则入栈
{
stack_push(S,k);
}
if(ve[e]+p->weiget>ve[k])
ve[k]=ve[e]+p->weiget;//寻找最大值
}
}
if(num==pit->vexnum)
return true;
else
return false;
}
void Critical_path(Graph pit)//关键路径算法
{
/*
三个辅助数组
vl,事件最晚发生时间
ee,活动最早发生时间
el,活动最晚发生时间
*/
int i,e,k;
int vl[MAX_SIZE];
int ee[MAX_SIZE];
int el[MAX_SIZE];
enode p;
if(!topology(pit,T))
cout<<"Error!!";
//寻找ve[]最大值,用最大值初始化vl,都是最后一个啦
i=ve[0];
for(int j=1;j<pit->vexnum;j++)
{
if(ve[j]>i)
i=ve[j];
}
///初始化vl/
for(int j=0;j<pit->vexnum;j++)
{
vl[j]=i;
}
while(!isempty(T))//按照拓扑排序求vl
{
for(stack_pop(T,e),p=pit->vex[e].next;p;p=p->next)//vl等于它后继ve-后继权重
{
cout<<"弹出"<<e;
k=p->data;
if(vl[k]-p->weiget<vl[e])
vl[e]=vl[k]-p->weiget;
}
}
cout<<endl<<"i ve vl"<<endl;
for(int i=0;i<pit->vexnum;i++)
{
cout<<i<<" "<<ve[i]<<" "<<vl[i];
if(ve[i]==vl[i])
cout<<" 关键路径经过的顶点";
cout<<endl;
}
/*路径<j,k>,ee最早发生活动=ve[j],el最晚发生活动=vl[k]-k的权重*/
cout<<" "<<"ee"<<" "<<"el"<<endl;
for(int i=0;i<pit->vexnum;i++)
{
for(p=pit->vex[i].next;p;p=p->next)
{
k=p->data;
ee[k]=ve[i];//只是暂时存放变量使用
el[k]=vl[k]-p->weiget;//只是暂时存放变量使用
cout<<pit->vex[i].data<<"->"<<pit->vex[k].data<<" ";
cout<<ee[k]<<" "<<el[k]<<" ";
if(ee[k]==el[k])
cout<<"关键活动";
cout<<endl;
}
}
}
int main()
{
stack_init(T);
Graph pit=creat_graph();
Critical_path(pit);
return 0;
}
正确输出: