2024 数据结构 拓扑排序邻接矩阵 解答题
第 41 题

2023 年 10 月 26 日,神州十七号载人飞船发射取得圆满成功,再次彰显了中国航天事业的辉煌成就。载人航天工程是包含众多子工程的复杂系统工程,为了保证工程的有序开展,需要明确各子工程的前导工程。以协调各子工程的实施。该问题可以简化、抽象为有向图的拓扑序列问题。已如有向图 G 采用邻接矩阵存储,类型定义如下:

typedef struct // 图的类型定义
{
    int numVertices, numEdges; // 图的顶点数和有向边数
    char verticesList[MAXV];   // 项点表,MAXV 为以定义常量
    int Edge[MAXV][MAXV];      // 邻接矩阵
} MGraph

请设计算法:int uniquely(MGraph G)。判定 G 是否存在唯一的拓扑序列,若是则返回 1,否则返回 0。要求:

(1) 给出算法的基本设计思想(4 分)

(2) 根据设计思想,采用 C 或 C++ 语言描述算法,关键之处给出注释(9 分)

拓扑排序 邻接矩阵

[tag_link]

1)算法基本设计思想输出拓扑序列的过程如下:依次从图中选取入度为 0 的点进行输出。确保拓扑序列唯一需要保证如下条件:在输出拓扑序列时,每一次有且仅有一个入度为 0 的顶点。所以这题最直观的思路就是进行 numEdges 轮遍历,如果每轮遍历只有一个顶点的入度为 0,则图中存在唯一的拓扑序列;否则不存在唯一的拓扑序列。

2)算法实现

int uniquely(MGraph g)
{
    int n = g.numVertices;
    int inDegrees[MAXV];

    /* 计算所有顶点的入度 */
    for (int v = 0; v < n; v++) {
        inDegrees[v] = 0;
        for (int i = 0; i < n; i++) {
            if (g.Edge[i][v] != 0)
                inDegrees[v] += g.Edge[i][v];
        }
    }

    /* 进行 n 轮拓扑删除 */
    for (int k = 0; k < n; k++) {

        int count0 = 0;   // 入度为 0 的顶点个数
        int v0 = -1;      // 本轮唯一可以选择的顶点

        /* 找所有入度为 0 的顶点 */
        for (int i = 0; i < n; i++) {
            if (inDegrees[i] == 0) {
                count0++;
                v0 = i;
            }
        }

        /* 若不是唯一一个,则拓扑序列不唯一 */
        if (count0 != 1) {
            return 0;
        }

        /* “删除”该顶点:将其入度设为 -1,避免重复选取 */
        inDegrees[v0] = -1;

        /* 更新其所有后继节点的入度 */
        for (int j = 0; j < n; j++) {
            if (g.Edge[v0][j] != 0)
                inDegrees[j]--;
        }
    }

    /* 所有步骤都唯一,拓扑序唯一 */
    return 1;
}