拓扑排序实现求施工的最短工期(邻接表存图)

为什么要找关键路径

拓扑排序:以某种偏序关系得出一个集合的全序

在拓扑排序中,把当前的网看成AOV网,活动都在结点,有向边表示先后依赖关系

实现:还是用栈或者队列实现,只要前驱变成0,进栈,如果栈都空了,但是还没找到所有的结点,说明有循环依赖,工程有死锁。​​​​​​

//利用拓扑路径法求有向图的关键路径//
#include<bits/stdc++.h>
using namespace std;
typedef int Status;
typedef int VertexType;
typedef char InfoType ;


typedef struct ArcNode//弧
{
    int adjvex;//值
    struct ArcNode* nextarc;//下一个
    InfoType *info;
    int weight;//完成工作的时间
}ArcNode;


typedef struct VNode//结点或者单个数组元素
{
    VertexType data;
    ArcNode *firstarc;//邻接表单个元素下的后继是以弧的形式存在的
}VNode,*AdjList;


typedef struct //邻接表
{
    AdjList vertices;
    int vexnum,arcnum;

}ALGraph;

//邻接表的创建

Status CreatDN(ALGraph &G)
{
    cin>>G.vexnum>>G.arcnum;
    for(int i=1;i<=G.vexnum;i++)//输入每个结点并且每个结点的后继都是空
    {
        cin>>G.vertices[i].data;
        G.vertices[i].firstarc=NULL;
    }

    for(int i=0;i<G.arcnum;i++)//输入弧
    {
        char v1,v2;
        int w,i,j;
        cin>>v1>>v2>>w;
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);
        ArcNode *arc=(ArcNode*)malloc(sizeof(ArcNode));//因为是个指针所以要malloc一下
        arc->weight=w;//弧的权值
        arc->adjvex=j;//出度为j
        arc->nextarc=G.vertices[i]->firstarc;
        G.vertices[i].firstarc=arc;
    }
    return OK;
}


//用栈实现拓扑排序的思想(部分函数没有实现)//这个函数实现与本题无关
Status TopologicalSort(ALGraph G)
{
    int *InDegree;
    InDegree=(int*)malloc(sizeof(int)*G.vexnum);
    GetInDegree(G,InDegree);//求每个结点的的入度个数
    InitStack(S);//初始化这个栈
    for(int i=1;i<=G.vexnum;i++)//找到第一个入度为0的点作为排序起点
    {
        if(!InDegree[i]) Push(S,i);
    }

    int count=0;
    while(!StackEmpty(S))//只要栈不为空
    {
        int num;
        Pop(S,num);//出来一个结点
        OutPutElem(G.vertices[num].data);//输出出来
        count++;//只要在栈里面输出一个点就加加

        for(ArcNode p=G.vertices[num];p!=NULL;p=p->nextarc)
        {//将目前结点的出度结点的入度都减一,入度为0的结点再入栈
          InDegree[p->adjvex]--;
          if(!InDegree[p->adjvex]) Push(S,p->adjvex);
        }

    }
    if(count<G.vexnum)return ERROR:
            else return OK;

}//T=O(n+e)


//对拓扑排序前期求所有结点的入度

void GetInDegree(ALGraph G,int &InDegree)
{
   memset(InDegree,0,sizeof(InDegree));
   for(int i=1;i<=G.vexnum;i++)
   {
      ArcNode* p=G.vertices[i].firstarc;
      while(p)
      {
          InDegree[p->adjvex]++;
          p=p->nextarc;
      }
   }
}


//拓扑排序并且保存从起点到每个结点的最长路的长度

Status GetVEandRvsTopoOrder(ALGraph &G,Stack &T)
{
    int *InDegree;
    int *vl;
    vl=(int*)malloc(sizeof(int)*G.vexnum);
    InDegree=(int*)malloc(sizeof(int)*G.vexnum);
    memset(vl,0,sizeof(vl));
    memset(InDegree,sizeof(InDegree));
    GetInDegree(G,InDegree);
    InitStack(S);
    InitStack(T);//用来存逆拓扑排序
    for(int i=1;i<=G.vexnum;i++)//找到所有的入度为0的结点而不是只找一个入度为0的点
    {
        if(InDegree[i]==0)
            Push(S,i);
    }
    int count=0;
    while(!StackEmpty(S))//只要栈不为0
    {
      int num;
      Pop(S,num);
      Push(T,num);
      count++;
      for(ArcNode*p=G.vertices[num].firstarc;p!=NULL;p=p->nextarc)
      {
         InDegree[p->adjvex]--;//把点和它连接的箭头删掉
         if(!InDegree[p->adjvex])Push(S,p->adjvex);//只要出现入度为0,入栈
         if(vl[num]+p->weight>vl[p->adjvex])
         {
             vl[p->adjvex]=vl[num]+p->weight;//数组存的就是从起点到
             //当前结点的最长路

         }
      }
    }
    if(count<G.vexnum)return ERROR;
     else return OK;
}

//求关键点
Status  CriticalPath(ALGraph G)
{
    InitStack(T);
    if(GetVEandRvsTopoOrder(G,T))return ERROR;//进行拓扑排序
    int *vl=(int*)malloc(sizeof(int)*(G.vexnum+1));//用来存最晚激活时间
    for(int i=1;i<=G.vexnum;i++)//
        vl[i]=ve[G.vexnum];//每个点的最晚开始时间
    //求一个结点的最晚开始时间,意思是保证工期的前提之下,从最晚工期往前推
    //当一个点的后继有多个的时候,为了保证后继结点都能完成,此节点的最晚开始时间,要找减之后的最小值
    int j;
    Pop(S,j);
    ArcNode* p=G.vertices[j].firstarc;
    while(p)
    {
        if(vl[j]>vl[p->adjvex]-p->weight)//存最小的
            vl[j]=vl[p->adjvex]-p->weight;
    }
    for(int i=1;i<=G.vexnum;i++)
    {
        ArcNode *q=G.vertices[i].firstarc;
        while(q)
        {
          int ee=ve[i];//最早激活时间
          int el=vl[q->adjvex]-p->weight;//最晚激活时间
          if(ee=el)//如果相等则为关键点
            cout<<i<<q->adjvex<<"是关键点"<<endl;
        }
    }
}














当AOV图看

1.进行拓扑排序,同时求出到每个结点的最长路径,最后一个结点的ve[]值就是最长路径就是最早激活时间。就是最短工期

2.找vl[],从后往前找,在栈T里面一个一个地出,这个结点的最晚激活时间就是它所有后继减去权值最小值,(因为如果有两个或者多个后继,要保证在最短工期完成后面的所有工作,所以尽量选早的)

3.最后求弧AOE图,弧ab的最早激活时间就是a的最早激活时间,最晚激活时间就是b-弧的权值。

4.只要ee==el这就是最短路径

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值