Kahn算法
无前趋的的顶点优先拓扑排序
每次取出入度为0的点,得到拓扑序列
1、先将所有入度为0的点放入一个队列,每次取出一个点放入拓扑序列中,并删除这个点的所有边。
2、如果删除一条边后该点的入度为0,则将该点放入队列,直到队列为空。
3、如果图中存在有向环的话,环上的所有点入度都不为0,所以不会被放入队列。
4、所以最后需要检查拓扑序列中的点数是否等于图中的点数,如果不等于,则说明图中存在有向环,排序失败。如果等于,则说明图中不存在有向环,排序成功。
时间复杂度为 O ( E + V ) O(E+V) O(E+V)
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 2005;
int t, n, m;
int in[N]; // 每个节点的度
queue<int> q;
vector<int> edge[N], topo; // topo为拓扑序列
void init()
{
for (int i = 1; i <= n; i++) {
edge[i].clear();
in[i] = 0;
}
while (!q.empty())
q.pop();
topo.clear();
}
bool toposort()
{
for (int i = 1; i <= n; i++) // n为节点的总数
if (in[i] == 0)
q.push(i); // 将度为0的节点放入队列
while (!q.empty()) {
int p = q.front(); q.pop(); // 选一个度为0的点出队
topo.push_back(p);
for (int i = 0; i < edge[p].size(); i++) {
int y = edge[p][i];
in[y]--;
if (in[y] == 0)
q.push(y);
}
}
if (topo.size() == n)
return true;
else
return false;
}
int main(void)
{
int a, b;
scanf("%d", &t);
while (t--){
scanf("%d%d", &n, &m);
init();
while (m--) {
scanf("%d%d", &a, &b);
edge[a].push_back(b);
in[b]++;
}
if (toposort()) {
for (int i = 0; i < topo.size(); i++)
printf("%d ", topo[i]);
printf("\n");
}
}
return 0;
}
DFS算法
无后继的的顶点优先拓扑排序
每次取出出度为0的点,得到的是拓扑序列的逆序
从1号点开始进行dfs,访问能够到达的点,并标记访问过的点(访问过的点之后不再访问),直至到达一个无路可走的点,将该点放入拓扑序列中。此时回到上一个点,重新进行访问,直到1号点dfs结束。
依次类推,直到最后的n号点dfs结束。
以一个点u为原点进行遍历时,使c[u]=-1,表示正在从点u进行搜索。
在遍历过程中如果到达了为-1的点,则说明回到了原点,即存在有向环,排序失败。
将点u所有能到达的点都访问过之后,则使c[u]=1,表示u已经访问过。
时间复杂度 O ( E + V ) O(E+V) O(E+V)
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 2005;
int t, n, m; // n为点的个数,m为边数
int c[N]; // 标记点是否访问过
bool G[N][N];
vector<int> topo; // 拓扑序列
void init()
{
memset(c, 0, sizeof c);
memset(G, 0, sizeof G);
topo.clear();
}
bool dfs(int u)
{
c[u] = -1; // 用于判断是否存在有向环
for (int v = 1; v <= n; v++)
if (G[u][v]) {
if (c[v] < 0) // 存在有向环
return false;
else if (!c[v])
dfs(v);
}
c[u] = 1; // 标记该点已经访问过
topo.push_back(u);
return true;
}
bool toposort()
{
for (int u = 1; u <= n; u++)
if (!c[u])
if (!dfs(u))
return false;
reverse(topo.begin(), topo.end());
return true;
}
int main(void)
{
int u, v;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
init();
while (m--) {
scanf("%d%d", &u, &v);
G[u][v] = 1;
}
if (toposort()) {
for (int i = 0; i < topo.size(); i++)
printf("%d ", topo[i]);
printf("\n");
}
}
return 0;
}
参考博客:
https://blog.youkuaiyun.com/qq_41713256/article/details/80805338
https://blog.youkuaiyun.com/juanlansexuehua/article/details/56875859