关键路径

工程中的关键活动和关键路径

#include <iostream>
using namespace std;

#define MVNum 100                           //最大顶点数
#define BDNum MVNum * (MVNum - 1)            //最大边数
#define OK 1    
#define ERROR 0 

typedef char VerTexType;

//- - - - -图的邻接表存储表示- - - - - 
typedef struct ArcNode {                        
    int adjvex;                          
    int weight;                                
    struct ArcNode *nextarc;                  
}ArcNode;

typedef struct VNode {
    VerTexType data;                        
    ArcNode *firstarc;                        
}VNode, AdjList[MVNum];                       

typedef struct {
    AdjList vertices;                         //邻接表 
    AdjList converse_vertices;                //逆邻接表
    int vexnum, arcnum;                      //图的当前顶点数和边数 
}ALGraph;

//- - - - -顺序栈的定义- - - - -
typedef struct {
    int *base;
    int *top;
    int stacksize;
}spStack;

int indegree[MVNum];                        //数组indegree存放个顶点的入度
int ve[BDNum];                                //事件vi的最早发生时间
int vl[BDNum];                                //事件vi的最迟发生时间
int topo[MVNum];                            //记录拓扑序列的顶点序号
spStack S;

//----------------栈的操作--------------------
void InitStack(spStack &S) {
    //栈的初始化
    S.base = new int[MVNum];
    if (!S.base)
        exit(1);
    S.top = S.base;
    S.stacksize = MVNum;
}

void Push(spStack &S, int i) {
    //入栈
    if (S.top - S.base == S.stacksize)
        return;
    *S.top++ = i;
}

void Pop(spStack &S, int &i) {
    //出栈
    if (S.top == S.base)
        return;
    i = *--S.top;
}

bool StackEmpty(spStack S) {
    //判断栈是否为空
    if (S.top == S.base)
        return true;
    return false;
}


int LocateVex(ALGraph G, VerTexType v) {
    //确定点v在G中的位置
    for (int i = 0; i < G.vexnum; ++i)
        if (G.vertices[i].data == v)
            return i;
    return -1;
}

int CreateUDG(ALGraph &G) {
    //创建有向图G的邻接表、逆邻接表
    int i, k;

    cout << "请输入总顶点数:";
    cin >> G.vexnum;
    cout << "请输入弧数:";
    cin >> G.arcnum;
    cout << "请依次输入各顶点:";
    for (i = 0; i < G.vexnum; ++i) {                  //输入各点,构造表头结点表
        cin >> G.vertices[i].data;                   //输入顶点值
        G.converse_vertices[i].data = G.vertices[i].data;
        //初始化表头结点的指针域为NULL 
        G.vertices[i].firstarc = NULL;
        G.converse_vertices[i].firstarc = NULL;
    }

    cout << "请输入各条弧和对应的权值:" << endl;

    for (k = 0; k < G.arcnum; ++k) {                    
        VerTexType v1, v2;
        int i, j, w;
        cin >> v1 >> v2 >> w;                    
        i = LocateVex(G, v1);  j = LocateVex(G, v2);
        ArcNode *p1 = new ArcNode;                   
        p1->adjvex = j;                               
        p1->nextarc = G.vertices[i].firstarc;  G.vertices[i].firstarc = p1;
        p1->weight = w;
        ArcNode *p2 = new ArcNode;                       
        p2->adjvex = i;                               
        p2->nextarc = G.converse_vertices[j].firstarc;  G.converse_vertices[j].firstarc = p2;
        p2->weight = w;
        
    }
    return OK;
}

void FindInDegree(ALGraph G) {
    //求出各顶点的入度存入数组indegree中 
    int i, count;

    for (i = 0; i < G.vexnum; i++) {
        count = 0;
        ArcNode *p = G.vertices[i].firstarc;
        if (p) {
            while (p) {
                p = p->nextarc;
                count++;
            }
        }
        indegree[i] = count;
    }
}

int TopologicalOrder(ALGraph G, int topo[]) {
    //有向图G采用邻接表存储结构 
    //若G无回路,则生成G的一个拓扑序列topo[]并返回OK,否则ERROR 
    int i, m;
    FindInDegree(G);                              //求出各顶点的入度存入数组indegree中 
    InitStack(S);                                  //栈S初始化为空 
    for (i = 0; i < G.vexnum; ++i)
        if (!indegree[i]) Push(S, i);             //入度为0者进栈 
    m = 0;                                       //对输出顶点计数,初始为0 
    while (!StackEmpty(S)) {                        //栈S非空 
        Pop(S, i);                              //将栈顶顶点vi出栈
        topo[m] = i;                                 //将vi保存在拓扑序列数组topo中 
        ++m;                                     //对输出顶点计数 
        ArcNode *p = G.vertices[i].firstarc;    //p指向vi的第一个邻接点 
        while (p) {
            int k = p->adjvex;                    //vk为vi的邻接点   
            --indegree[k];                       //vi的每个邻接点的入度减1 
            if (indegree[k] == 0)  Push(S, k);    //若入度减为0,则入栈 
            p = p->nextarc;                        //p指向顶点vi下一个邻接结点 
        }
    }

    if (m < G.vexnum)  return ERROR;                //该有向图有回路 
    else return OK;
}

int CriticalPath(ALGraph G) {
    //G为邻接表存储的有向网,输出G的各项关键活动
    int n, i, k, j, e, l;
    if (!TopologicalOrder(G, topo))  return ERROR;
    //调用拓扑排序算法,使拓扑序列保存在topo中,若调用失败,则存在有向环,返回ERROR 
    n = G.vexnum;                                  //n为顶点个数 
    for (i = 0; i < n; i++)                       //给每个事件的最早发生时间置初值0 
        ve[i] = 0;


    /*――――――――――按拓扑次序求每个事件的最早发生时间-――――-―――――*/
    for (i = 0; i < n; i++) {
        k = topo[i];                               //取得拓扑序列中的顶点序号k             
        ArcNode *p = G.vertices[k].firstarc;    //p指向k的第一个邻接顶点  
        while (p != NULL) {                        //依次更新k的所有邻接顶点的最早发生时间   
            j = p->adjvex;                       //j为邻接顶点的序号                   
            if (ve[j] < ve[k] + p->weight)        //更新顶点j的最早发生时间ve[j] 
                ve[j] = ve[k] + p->weight;
            p = p->nextarc;                      //p指向k的下一个邻接顶点  
        }  
    }  

    for (i = 0; i<n; i++)                             //给每个事件的最迟发生时间置初值ve[n-1] 
        vl[i] = ve[n - 1];

    /*――――――――――按逆拓扑次序求每个事件的最迟发生时间-――――-―――――*/
    for (i = n - 1; i >= 0; i--) {
        k = topo[i];                               //取得拓扑序列中的顶点序号k             
        ArcNode *p = G.vertices[k].firstarc;    //p指向k的第一个邻接顶点  
        while (p != NULL) {                        //根据k的邻接点,更新k的最迟发生时间   
            j = p->adjvex;                      //j为邻接顶点的序号                   
            if (vl[k] > vl[j] - p->weight)        //更新顶点k的最迟发生时间vl[k] 
                vl[k] = vl[j] - p->weight;
            p = p->nextarc;                      //p指向k的下一个邻接顶点  
        }
    } 

     /*――――――――――――判断每一活动是否为关键活动-――――――-―――――*/
    cout << "关键路径为:" << endl;
    for (i = 0; i < n; i++) {                        //每次循环针对vi为活动开始点的所有活动 
        ArcNode *p = G.vertices[i].firstarc;    //p指向i的第一个邻接顶点  
        while (p != NULL) {
            j = p->adjvex;                         //j为i的邻接顶点的序号    
            e = ve[i];                             //计算活动<vi, vj>的最早开始时间 
            l = vl[j] - p->weight;              //计算活动<vi, vj>的最迟开始时间 
            if (e == l)                           //若为关键活动,则输出<vi, vj> 
                cout << G.vertices[i].data << G.vertices[j].data << " ";
            p = p->nextarc;                      //p指向i的下一个邻接顶点  
        } 
    }  
    return OK;
}

int main()
{
    ALGraph G;
    CreateUDG(G);               
    if (!CriticalPath(G))
        cout << "网中存在环,无法进行拓扑排序!" << endl;
    return OK;
}
原文地址:https://www.cnblogs.com/cjwen/p/11177871.html