【算法02】拓扑排序

1. 拓扑排序讲的是一件什么事呢?

就拿学习来说,学习有时候讲究先后顺序,就是你得先修完某个前导课程,你才能开启后续的更高阶的课程。我们可以把这样的关系反映到一张由结点和有向边构成的有向图中。拓扑排序就是遍历这张图中的所有结点,同时确保当遍历到每一个结点时,所有该节点的前置结点都已经遍历过了(这就要求图中不能有环)。我们把遍历所有结点得到的顺序序列称为拓扑序列。拓扑排序就是求这样的一个个序列

由此可见拓扑序列并不唯一。所以拓扑排序的结果也不唯一。

同时我们还可以利用不能成环这一性质,使用拓扑排序来判断一个图是否成环

求解方法就是:不断取出图中度为0的结点,然后所有被该结点所指的结点的入度-1

2. 用队列方式求解拓扑排序

/*************************************************************************
        > File Name: toposort.cpp
        > Author: jby
        > Mail: 
        > Created Time: Sun 16 Jul 2023 08:47:26 AM CST
 ************************************************************************/

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

struct edge {
    int e, next;
};

edge edg[100005];
int n ,m, head[105], in_degree[105], ans[105], cnt;

int main() {
    memset(head, -1, sizeof(head));
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        edg[i].e = b;
        edg[i].next = head[a];
        head[a] = i;
        in_degree[b]++; // 统计入度
    }
    queue<int> que;
    for (int i = 1; i <= n; i++) {
        if (in_degree[i] == 0) {
            que.push(i);
        }
    }
    while (!que.empty()) {
        int temp = que.front();
        que.pop();
        ans[cnt++] = temp;
        if (cnt == n) {
            for (int i = 0; i < n; i++) {
                cout << ans[i] << " ";
            }
            cout << endl;
            return 0;
        }
        for (int i = head[temp]; i != -1; i = edg[i].next) {
            int e = edg[i].e;
            in_degree[e]--;
            if (in_degree[e] == 0) {
                que.push(e);
            }
        }
    }
    // 退出while循环,说明成环了
    cout << "have loop" << endl;
    return 0;
}

 3. 用递归和回溯获取所有拓扑排序

/*************************************************************************
        > File Name: alltoposort.cpp
        > Author: jby
        > Mail: 
        > Created Time: Sun 16 Jul 2023 09:24:03 AM CST
 ************************************************************************/

#include<iostream>
#include<vector>
using namespace std;

int n, m, ans[105], in_degree[105], mark[105];

void func(int now, vector<vector<int> > &edg) {
    // now:当前遍历到第几个元素
    if (now == n + 1) {
        for (int i = 1; i <= n; i++) {
            cout << ans[i] << " ";
        }
        cout << endl;
        return ;
    }
    for (int i = 1; i <= n; i++) {
        if (in_degree[i] == 0 && mark[i] == 0) {
            ans[now] = i;
            mark[i] = 1;
            for (int j = 0; j < edg[i].size(); j++) {
                in_degree[edg[i][j]]--;
            }
            func(now + 1, edg);
            for (int j = 0; j < edg[i].size(); j++) {
                in_degree[edg[i][j]]++;
            }
            mark[i] = 0;
        }
    }
}

int main() {
    cin >> n >> m;
    vector<vector<int> > edg(n + 1, vector<int>());
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        edg[a].push_back(b);
        in_degree[b]++;
    }
    func(1, edg);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值