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;
}