兰州大学数据结构实验6:有向图的拓扑排序和逆拓扑排序

实验内容

查找工程图的关键活动

基本内容:

对于给定的如下有向工程施工图,找出该工程图的关键活动。

IMG_257

实验思路:

采取邻接矩阵的方式存储图。

第一步:利用拓扑排序过程计算每个节点的最早开始时间Ve

第二步:利用第一步中的到的拓扑序列的逆序,计算每个节点的最迟开始时间Vl

第三步:利用Ve和Vl计算每个活动的最早开始时间和最迟开始时间e,l

第四步:从起点开始,遍历邻接表中的每条边,若该边的e=l,则此边代表的活动是关键活动,输出

代码

#include <stdio.h>

#include <stdlib.h>

#define max 10000

int main()

{

    int u,v,w;

    int count=1;

    /*创建一个邻接矩阵*/

    int nodenum/*节点数*/,arcnum/*边数*/,i,j,k,z;

    printf("请输入节点数目和边数:");

    scanf("%d",&nodenum);

    scanf("%d",&arcnum);

    int adj[nodenum+1][nodenum+1];//adjmatrix

    /*初始化矩阵*/

    for (i=0; i<nodenum+1; i++)

    {

        for (j=1; j<nodenum+1; j++)

        {

            adj[i][j]=max;

        }

    }

    /*adj的出度入度记录初始化*/

    for (k=0; k<nodenum+1; k++)

    {

        adj[0][k]=0;//出度

        adj[k][0]=0;//入度

    }

    int ve[nodenum+1],vl[nodenum+1],ae[arcnum+1],al[arcnum+1];/*有点浪费第一个【0】的位置,但是后面不费脑子*/

    int s[nodenum]/*栈*/,arc[arcnum+1][2]/*记录边邻接的有哪些节点*/;

    /*输入边与权值来构成邻接矩阵*/

    printf("请输入边和权值:\n");

    j=0;

    while (j<arcnum)

    {

        scanf("%d%d%d",&u,&v,&w);

        adj[u][v]=w;

        adj[v][0]++;

        adj[0][u]++;

        arc[j+1][0]=u;

        arc[j+1][1]=v;

        j++;

    }

    /*求ve*/

    /*初始化ve*/

    for (i=0; i<nodenum; i++)

    {

        ve[i]=0;

    }

    /*搜索一遍入度为0的节点,让其对应的ve最早发生时间为0,且节点入栈*/

    j=-1;

    for (i=1; i<nodenum+1; i++)

    {

        if(adj[i][0]==0)

        {

            j++;

            s[j]=i;

        }

    }

    /*用栈更新每个事件的最早发生时间*/

    while (j>=0)

    {

        k=s[j];

        j--;/*退栈*/

        for (z=1; z<nodenum+1; z++)/*将这个退栈的这个元素所对应的所有结点都遍历*/

        {

            if (z==k)continue;

            if (adj[k][z]>=max)continue;/*若这个退栈的结点与当前遍历的节点没有路径就进行下一个遍历*/

            else

            {

                adj[z][0]--;/*有路径就将这个对应的结点入度减一*/

                if (adj[z][0]==0) /*若节点入度已经降为0就入栈*/

                {

                    j++;

                    s[j]=z;

                    count++;

                }

            }

            if (adj[k][z]+ve[k]<ve[z])continue;/*如果当前的事件已经是最早发生时间了,就跳过*/

            else

            {

                ve[z]=adj[k][z]+ve[k];/*此时得出的是最晚的发生时间则替代当前的节点*/

            }

        }

    }

    if(count!=nodenum)printf("这个图有环!不能得出关键活动与关键路径!");

    /*求vl*/

    /*初始化vl*/

    for (i=0; i<nodenum; i++)

    {

        vl[i]=max;

    }

    /*搜索一遍出度为0的节点,节点入栈*/

    j=-1;

    for (i=1; i<nodenum+1; i++)

    {

        if(adj[0][i]==0)

        {

            vl[i]=ve[i];

            j++;

            s[j]=i;

        }

    }

    while (j>=0)

    {

        k=s[j];

        j--;/*退栈*/

        for (z=1; z<nodenum+1; z++)/*将这个退栈的这个元素所对应的所有结点都遍历*/

        {

            if (z==k)continue;

            if (adj[z][k]>=max)continue;/*若这个退栈的结点与当前遍历的节点没有路径就进行下一个遍历*/

            else

            {

                adj[0][z]--;/*有路径就将这个对应的结点出度减一*/

                if (adj[0][z]==0) /*若节点出度已经降为0就入栈*/

                {

                    j++;

                    s[j]=z;

                }

            }

            if (vl[k]-adj[z][k]<vl[z])vl[z]=vl[k]-adj[z][k];/*此时得出的是最晚的发生时间则替代当前的节点*/

        }

    }

    /*用ve与vl对应着每条边的两个结点与arc来生成ae与al*/

    for (i=1; i<arcnum+1; i++)

    {

        ae[i]=ve[arc[i][0]];

        al[i]=vl[arc[i][1]]-adj[arc[i][0]][arc[i][1]];

    }

    int l,o;

    //print adj;

    printf("邻接矩阵:\n");

    for (l=0; l<nodenum+1; l++)

    {

        for (o=0; o<nodenum+1; o++)

        {

            printf("%7d ",adj[l][o]);

        }

        printf("\n");

    }

    printf("\n");

    //print ve,vl,ae,al;

    printf("各结点的最早发生时间(ve):");

    for (l=1; l<nodenum+1; l++)

    {

        printf("%d ",ve[l]);

    }

    printf("\n");

    printf("各结点的最晚发生时间(vl):");

    for (l=1; l<nodenum+1; l++)

    {

        printf("%d ",vl[l]);

    }

    printf("\n");

    printf("各活动的最早开始时间(ae):");

    for (l=1; l<arcnum+1; l++)

    {

        printf("%d ",ae[l]);

    }

    printf("\n");

    printf("各活动的最晚开始时间(al):");

    for (l=1; l<arcnum+1; l++)

    {

        printf("%d ",al[l]);

    }

    printf("\n\n");

    //print important arc

    printf("关键活动:");

    for (l=1; l<arcnum+1; l++)

    {

        if (ae[l]==al[l]) printf("a%d ",l);

    }

    return 0;

007D

运行结果:

输入数据:

请输入节点数目和边数:9 11

请输入边和权值:

1 2 6

1 3 4

1 4 5

2 5 1

3 5 1

4 6 2

5 7 9

5 8 7

6 8 4

7 9 2

8 9 4

输出结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值