关键路径

如果说拓扑排序是为了找到有向无环图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;
}

正确输出:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值