有向无环图

有向无环图

简称DAG图是用来描述一项工程或系统的进行过程的有效工具。

AOV网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为AOV网,是无权有向无环图
AOE网:用顶点表示事件,弧表示活动权表示活动持续的时间称为AOE网,是带权有向无环图

拓扑排序

拓扑排序就是将AOV网中所有顶点按流程次序排成一个线性序列,该线性序列并不唯一,其过程为:

(1)在有向图中选一个无前驱的顶点且输出它
(2)从图中删除该顶点和并清除以它为前驱的入度
(3)重复一、二步骤,直至不存在无入度为0的顶点
(4)若此时输出的顶点数小于有向图中的顶点数,则说明有向图中存在环,否则输出的顶点序列即为一个拓扑序列。

在这里插入图片描述

在实际操作中我们并不一定需要直接对图进行操作,可以借助辅助结构比如栈和队列来实现拓扑排序

实现代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 100
//邻接表
typedef struct ArcNode
{
    int adj;
    struct ArcNode *next;
} ArcNode;
typedef struct VNode
{
    char data;
    ArcNode *First;
} VNode, AdjList[MAXSIZE];
typedef struct
{
    AdjList ver;
    int vexnum, arcnum;
} ALGraph;
ALGraph G;
//栈
typedef struct Stack
{
    int *base;
    int *top;
    int stacksize;
} STACK;
STACK S;
//栈的操作
int InitStack()
{
    S.base = malloc(MAXSIZE * sizeof(int));
    if (!S.base)
    {
        return 0;
    }
    else
    {
        S.top = S.base;
        S.stacksize = MAXSIZE;
        return 1;
    }
}
int StackEmpty()
{
    return S.top == S.base;
}
int Push(int e)
{
    if (S.top - S.base == S.stacksize)
    {
        return 0;
    }
    else
    {
        *S.top++ = e;
        S.stacksize--;
        return 1;
    }
}
int Pop()
{
    if (S.top == S.base)
    {
        return 0;
    }
    else
    {
        --S.top;
        return 1;
    }
}
int GetTop()
{
    if (S.top != S.base)
    {
        return *(S.top - 1);
    }
}
//创建邻接表表示图
void CreateGraph()
{
    ArcNode *p, *q;
    int x, y;
    printf("Please input the number of vexs:");
    scanf("%d", &G.vexnum);
    printf("Please input the number of arcs:");
    scanf("%d", &G.arcnum);
    getchar();
    for (int i = 1; i <= G.vexnum; i++)
    {
        printf("Please input the %dth vex:", i);
        scanf("%c", &G.ver[i].data);
        getchar();
    }
    for (int i = 1; i <= G.arcnum; i++)
    {
        printf("Please input the start:");
        scanf("%d", &x);
        printf("Please input the end:");
        scanf("%d", &y);
        if (G.ver[x].First)
        {
            p = G.ver[x].First;
            while (p->next)
            {
                p = p->next;
            }
            q = malloc(sizeof(ArcNode));
            q->adj = y;
            p->next = q;
            q->next = NULL;
        }
        else
        {
            q = malloc(sizeof(ArcNode));
            q->adj = y;
            q->next = NULL;
            G.ver[x].First = q;
        }
    }
    return;
}
//拓扑排序
bool TopoSort(int topo[])
{
    int In[MAXSIZE] = {0};
    ArcNode *p;
    for (int i = 1; i <= G.vexnum; i++)
    {
        p = G.ver[i].First;
        while (p)
        {
            In[p->adj]++;
            p = p->next;
        }
    }
    for (int i = 1; i <= G.vexnum; i++)
    {
        if (!In[i])
        {
            Push(i);
        }
    }
    int s, t=0,cnt = 0;
    while (!StackEmpty())
    {
        s = GetTop();
        topo[t++]=s;
        Pop();
        printf("%c\n", G.ver[s].data);
        cnt++;
        p = G.ver[s].First;
        while (p)
        {
            In[p->adj]--;
            if (!In[p->adj])
            {
                Push(p->adj);
                p = p->next;
            }
            else
            {
                p = p->next;
                continue;
            }
        }
    }
    if (cnt < G.vexnum)
    {
        return false;
    }
    else
    {
        return true;
    }
}
int main()
{
    InitStack();
    CreateGraph();
    int topo[MAXSIZE];
    if (TopoSort(topo))
    {
        printf("The graph has no circle!\n");
    }
    else
    {
        printf("The graph has circle!\n");
    }
    return 0;
}

时间复杂度:O(n+e)

关键路径

一个工程在无环的情况下,网只有一个入度为0的点称为源点,只有一个出度为0的点称为汇点

关键路径就是从源点到汇点带权路径长度最长的路径,也是工程完成的最短时间,关键路径上的活动称为关键活动,关键活动是影响整个工程进度的关键,它们的提前或拖延将将使整个工程提前或拖延。

在这里插入图片描述

求解流程:
(1)利用拓扑序列求出每个事件的最早发生时间ve(i)
(2)按逆拓扑序列求出每个事件的最迟发生时间vl(i)
(3)求出每个活动的最早开始时间e(i)
(4)求出每个活动的最晚开始时间l(i)
(5)找出e(i)=l(i)的活动,即为关键活动,其形成的由源点到汇点的每一条路径就是关键路径,关键路径有可能不止一条。

实现代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 100
//邻接表
typedef struct ArcNode
{
    int adj;
    int weight;
    struct ArcNode *next;
} ArcNode;
typedef struct VNode
{
    char data;
    ArcNode *First;
} VNode, AdjList[MAXSIZE];
typedef struct
{
    AdjList ver;
    int vexnum, arcnum;
} ALGraph;
ALGraph G;
int topo[MAXSIZE];
//栈
typedef struct Stack
{
    int *base;
    int *top;
    int stacksize;
} STACK;
STACK S;
//栈的操作
int InitStack()
{
    S.base = malloc(MAXSIZE * sizeof(int));
    if (!S.base)
    {
        return 0;
    }
    else
    {
        S.top = S.base;
        S.stacksize = MAXSIZE;
        return 1;
    }
}
int StackEmpty()
{
    return S.top == S.base;
}
int Push(int e)
{
    if (S.top - S.base == S.stacksize)
    {
        return 0;
    }
    else
    {
        *S.top++ = e;
        S.stacksize--;
        return 1;
    }
}
int Pop()
{
    if (S.top == S.base)
    {
        return 0;
    }
    else
    {
        --S.top;
        return 1;
    }
}
int GetTop()
{
    if (S.top != S.base)
    {
        return *(S.top - 1);
    }
}
//创建邻接表表示图
void CreateGraph()
{
    ArcNode *p, *q;
    int x, y, z;
    printf("Please input the number of vexs:");
    scanf("%d", &G.vexnum);
    printf("Please input the number of arcs:");
    scanf("%d", &G.arcnum);
    getchar();
    for (int i = 1; i <= G.vexnum; i++)
    {
        printf("Please input the %dth vex:", i);
        scanf("%c", &G.ver[i].data);
        getchar();
    }
    for (int i = 1; i <= G.arcnum; i++)
    {
        printf("Please input the start:");
        scanf("%d", &x);
        printf("Please input the end:");
        scanf("%d", &y);
        printf("Please input the weight:");
        scanf("%d", &z);
        if (G.ver[x].First)
        {
            p = G.ver[x].First;
            while (p->next)
            {
                p = p->next;
            }
            q = malloc(sizeof(ArcNode));
            q->adj = y;
            q->weight = z;
            p->next = q;
            q->next = NULL;
        }
        else
        {
            q = malloc(sizeof(ArcNode));
            q->adj = y;
            q->weight = z;
            q->next = NULL;
            G.ver[x].First = q;
        }
    }
    return;
}
//拓扑排序
bool TopoSort()
{
    int In[MAXSIZE] = {0};
    ArcNode *p;
    for (int i = 1; i <= G.vexnum; i++)
    {
        p = G.ver[i].First;
        while (p)
        {
            In[p->adj]++;
            p = p->next;
        }
    }
    for (int i = 1; i <= G.vexnum; i++)
    {
        if (!In[i])
        {
            Push(i);
        }
    }
    int s, t = 1, cnt = 0;
    printf("The topo sort is:\n");
    while (!StackEmpty())
    {
        s = GetTop();
        topo[t++] = s;
        Pop();
        printf("%c\n", G.ver[s].data);
        cnt++;
        p = G.ver[s].First;
        while (p)
        {
            In[p->adj]--;
            if (!In[p->adj])
            {
                Push(p->adj);
                p = p->next;
            }
            else
            {
                p = p->next;
                continue;
            }
        }
    }
    if (cnt < G.vexnum)
    {
        return false;
    }
    else
    {
        return true;
    }
}
//关键路径
void CriticalPath()
{
    ArcNode *p;
    TopoSort();
    int ve[MAXSIZE], vl[MAXSIZE], e, j, l, k;
    for (int i = 1; i <= G.vexnum; i++)
    {
        ve[i] = 0;
    }
    for (int i = 1; i <= G.vexnum; i++)
    {
        k = topo[i];
        p = G.ver[k].First;
        while (p)
        {
            j = p->adj;
            if (ve[j] < ve[k] + p->weight)
            {
                ve[j] = ve[k] + p->weight;
            }
            p = p->next;
        }
    }
    for (int i = 1; i <= G.vexnum; i++)
    {
        vl[i] = ve[G.vexnum];
    }
    for (int i = G.vexnum; i >= 1; i--)
    {
        k = topo[i];
        p = G.ver[k].First;
        while (p)
        {
            j = p->adj;
            if (vl[k] > vl[j] - p->weight)
            {
                vl[k] = vl[j] - p->weight;
            }
            p = p->next;
        }
    }
    printf("The CriticalPath is:\n");
    for (int i = 1; i <= G.vexnum; i++)
    {
        p = G.ver[i].First;
        while (p)
        {
            j = p->adj;
            e = ve[i];
            l = vl[j] - p->weight;
            if (e == l)
            {
                printf("%c->%c\n", G.ver[i].data, G.ver[j].data);
            }
            p = p->next;
        }
    }
    return;
}
int main()
{
    InitStack();
    CreateGraph();
    CriticalPath();
    return 0;
}

时间复杂度:O(n+e)

实践证明,用AOE网对于估算工程完成的时间是十分有用的。我们再实施工程时对关键路径上的关键活动要十分关注,因为关键路径决定了工期的长短,与此同时,我们还可以对非关键路径上的活动进行合理安排。若网中有多条关键路径,那么单一提高一条关键路径上的是速度还不能导致整个工期缩短,必须同时提高所有关键路径上的活动速度才能达到期望值。

Python是一种流行的编程语言,可以用来处理图论问题。在Python中,可以使用图的数据结构来表示和操作有向无环图(Directed Acyclic Graph,DAG)。有向无环图是一种图结构,其中的边都是有方向的,并且不存在任何形成环路的路径。 在Python中,可以使用各种图论库来处理有向无环图,例如networkx、graph-tool等。这些库提供了一系列的函数和方法,可以用来创建、操作和分析有向无环图。 具体来说,要判断一个图是否是有向无环图,可以使用拓扑排序算法。拓扑排序是一种对有向无环图进行排序的算法,它将图中的节点按照依赖关系进行排序,使得每个节点在排列中都位于它的依赖节点之后。 在Python中,可以使用拓扑排序算法来判断一个图是否是有向无环图。如果拓扑排序成功完成,并且没有环路存在,则可以确定该图是有向无环图。 下面是一个示例代码,演示了如何使用Python和networkx库来判断一个图是否是有向无环图: ```python import networkx as nx # 创建一个有向无环图 G = nx.DiGraph() G.add_edges_from([(1, 2), (2, 3), (3, 4)]) # 判断图是否是有向无环图 if nx.is_directed_acyclic_graph(G): print("该图是有向无环图") else: print("该图不是有向无环图") ``` 在上面的示例中,我们首先使用networkx库创建了一个有向无环图G,然后使用`is_directed_acyclic_graph`函数判断该图是否是有向无环图。如果返回结果为True,则说明该图是有向无环图,否则说明该图不是有向无环图。 希望这个示例对你有所帮助。如果你需要更多关于有向无环图的信息,可以参考networkx库的文档或者其他相关资料。<span class="em">1</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值