【每日算法】AB13 拓扑排序

一、题目

描述

给定一个包含n个点m条边的有向无环图,求出该图的拓扑序。若图的拓扑序不唯一,输出任意合法的拓扑序即可。若该图不能拓扑排序,输出-1。

输入描述:

第一行输入两个整数n,m ( 1≤n,m≤2⋅10^5),表示点的个数和边的条数。接下来的mm行,每行输入两个整数ui,vi(1≤u,v≤n),表示ui到vi之间有一条有向边。

输出描述:

若图存在拓扑序,输出一行n个整数,表示拓扑序。否则输出-1。

二、代码

#include 
#include 

// 图中节点的结构,分别为邻接点(表示为数组)、编号、入度、出度
typedef struct vNode{
    struct vNode** adj;
    int index;
    int inNum;
    int outNum;
}vNode;

int main() {
    int nodeNum, edgeNum;
    scanf("%d%d", &nodeNum, &edgeNum);
    int cover[nodeNum]; // i点是否已经被处理
    struct vNode* gragh[nodeNum];
    // 初始化图中节点
    for(int i = 0; i < nodeNum; i ++){
        gragh[i] = (struct vNode*)malloc(sizeof(struct vNode));
        gragh[i]->index = i;
        gragh[i]->inNum = 0;
        gragh[i]->outNum = 0;
        gragh[i]->adj = NULL;
        cover[i] = 0;
    }
    // 边的输入
    int v1, v2;
    for(int i = 0; i < edgeNum; i ++){
        scanf("%d%d", &v1, &v2);
        v1--;
        v2--;
        gragh[v2]->inNum ++;
        gragh[v1]->adj = realloc(gragh[v1]->adj, sizeof(struct vNode*) * (++ gragh[v1]->outNum));
        gragh[v1]->adj[gragh[v1]->outNum - 1] = gragh[v2];
    }
    int doneV = 0;
    int result[nodeNum]; // 存放结果
    while(doneV != nodeNum){
        int stillUpdate = 0; // 标志是否可以退出循环(如果遍历了一遍以后没有要输出的节点,那么停止)
        for(int i = 0; i < nodeNum; i ++){
            if(cover[i] == 1){
                continue;
            }
            if(gragh[i]->inNum == 0){
                result[doneV ++] = i + 1;
                stillUpdate = 1;
                cover[i] = 1;
                // printf("delete %d cover:%d, doneV:%d, outNum %d\n", i+1, cover[i], doneV, gragh[i]->outNum);
                for(int j = 0;j < gragh[i]->outNum; j ++){
                    gragh[i]->adj[j]->inNum --;
                }
                // 记得释放内存
                free(gragh[i]);
                gragh[i] = NULL;
            }
        }
        if(!stillUpdate){
            break;
        }
    }
    if(doneV == nodeNum){
        for(int i = 0; i < nodeNum-1; i ++){
            printf("%d ", result[i]);
        }
        printf("%d", result[nodeNum - 1]);
    }else{
        printf("-1");
    }
    return 0;
}

三、总结

很久没有做和图相关的题了,有点生疏,这里用一个数组存放图中的每一个节点,每个节点的邻接点也用数组存放,同时记录每个节点的入度出度和编号。
首先是一个大循环,在大循环里,循环遍历每一个点,输出入度为0的点,如果一个大循环下来,没有要输出的点,那么退出大循环。

你可能感兴趣的:(算法,算法,c语言,开发语言,数据结构)