拓扑排序Kahn算法与DFS算法

拓扑排序

给定一个有向无环图(DAG),排出所有顶点的一个序列A满足:对于图中每条有向边(x,y),x在A中都出现在y之前,则A是该图中的顶点的一个拓扑序

拓扑排序可以判断 有向图中是否有环 ,可以生成拓扑序列

Kahn(卡恩)算法

  • e[x]存点x的邻点,res存拓扑序列,d[x]存x的入度

算法流程:核心用队列维护一个入度为0的节点的集合。

  1. 初始化,队列q压入所有入度为0的点;
  2. 每次从q中取出一个点x放入数组res;
  3. 然后将×的所有出边删除。若将边(x,y)删除后,y的入度变为0,则将y压入q中
  4. 不断重复2,3过程,直到队列q为空。
  5. res中的元素个数等于n,则有拓扑序;否则,有环。

题目-有向图的拓扑序列

链接:https://www.acwing.com/problem/content/850/

给定一个 n n n 个点 m m m 条边的有向图,点的编号是 1 1 1 n n n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 − 1 -1 1

若一个由图中所有点构成的序列 A A A 满足:对于图中的每条边 ( x , y ) (x, y) (x,y) x x x A A A 中都出现在 y y y 之前,则称 A A A 是该图的一个拓扑序列。

输入格式

第一行包含两个整数 n n n m m m

接下来 m m m 行,每行包含两个整数 x x x y y y,表示存在一条从点 x x x 到点 y y y 的有向边 ( x , y ) (x, y) (x,y)

输出格式

共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 − 1 -1 1

数据范围

1 ≤ n , m ≤ 1 0 5 1 \le n,m \le 10^5 1n,m105

输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
代码
#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 1e5 + 10;
int n, m;
vector<int> e[N], res;
vector<int> d(N);

bool topsort() {
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (d[i] == 0) q.push(i);
    }
    while (q.size()) {
        auto t = q.front();
        q.pop();
        res.push_back(t);
        for (auto y: e[t]) {
            if (--d[y] == 0) q.push(y);
        }
    }
    return res.size() == n;
}


signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        d[y]++;
    }
    if (topsort()) {
        for (const auto &item: res) {
            cout << item << " ";
        }
    } else {
        cout << -1 << endl;
    }
    return 0;
}

DFS算法

  • e[x]存点x的邻点,res存拓扑序列,d[x]存x的入度

算法的核心是变色法,一路搜一路给点变色,如果有拓扑序,每个点的颜色都会从0→-1→1,经历三次变色。

  1. 初始状态,所有点染色为0。
  2. 枚举每个点,进入×点,把x染色为-1。然后,枚举x的儿子y,如果y的颜色为0,说明没碰过该点,进入y继续走,
  3. 如果枚举完×的儿子,没发现环,则×染色为1,并把×压入tp数组
  4. 如果发现有个熊孩子的颜色为-1,说明回到了祖先节点,发现了环,则一路返回false,退出程序

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 1e5 + 10;
vector<int> e[N], res, c(N);
int n, m;

int dfs(int x) {
    c[x] = -1;
    for (auto y: e[x]) {
        if (c[y] == -1) return 0;//有环
        else if (c[y] == 0) {
            int t = dfs(y);
            if (t == 0) return 0;
        }
    }
    c[x] = 1;
    res.push_back(x);
    return 1;
}

bool topsort() {
    for (int i = 1; i <= n; i++) {
        if (c[i] == 0) {
            int t = dfs(i);
            if (t == 0) return 0;
        }
    }
    std::reverse(res.begin(), res.end());
    return 1;
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
    }
    if (topsort()) {
        for (const auto &item: res) {
            cout << item << " ";
        }
    } else {
        cout << -1 << endl;
    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是用C语言实现拓扑排序Kahn算法DFS算法的示例代码: 1. 拓扑排序Kahn算法: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 struct Node { int data; struct Node* next; }; struct Graph { int numVertices; struct Node** adjLists; int* indegree; }; struct Node* createNode(int data) { struct Node* newNode = malloc(sizeof(struct Node)); newNode->data = data; newNode->next = NULL; return newNode; } struct Graph* createGraph(int vertices) { struct Graph* graph = malloc(sizeof(struct Graph)); graph->numVertices = vertices; graph->adjLists = malloc(vertices * sizeof(struct Node*)); graph->indegree = malloc(vertices * sizeof(int)); int i; for (i = 0; i < vertices; i++) { graph->adjLists[i] = NULL; graph->indegree[i] = 0; } return graph; } void addEdge(struct Graph* graph, int src, int dest) { struct Node* newNode = createNode(dest); newNode->next = graph->adjLists[src]; graph->adjLists[src] = newNode; graph->indegree[dest]++; } void topologicalSort(struct Graph* graph) { int* result = malloc(graph->numVertices * sizeof(int)); int front = 0, rear = 0; int* indegree = graph->indegree; int i; for (i = 0; i < graph->numVertices; i++) { if (indegree[i] == 0) { result[rear++] = i; } } while (front != rear) { int currentVertex = result[front++]; struct Node* temp = graph->adjLists[currentVertex]; while (temp) { int adjVertex = temp->data; indegree[adjVertex]--; if (indegree[adjVertex] == 0) { result[rear++] = adjVertex; } temp = temp->next; } } if (rear != graph->numVertices) { printf("Graph contains a cycle!\n"); return; } printf("Topological Sort:"); for (i = 0; i < graph->numVertices; i++) { printf(" %d", result[i]); } printf("\n"); } int main() { int vertices, edges; printf("Enter the number of vertices: "); scanf("%d", &vertices); printf("Enter the number of edges: "); scanf("%d", &edges); struct Graph* graph = createGraph(vertices); int i, src, dest; for (i = 0; i < edges; i++) { printf("Enter edge %d (source destination): ", i+1); scanf("%d %d", &src, &dest); addEdge(graph, src, dest); } topologicalSort(graph); return 0; } ``` 2. 拓扑排序DFS算法: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 struct Node { int data; struct Node* next; }; struct Graph { int numVertices; struct Node** adjLists; int* visited; }; struct Node* createNode(int data) { struct Node* newNode = malloc(sizeof(struct Node)); newNode->data = data; newNode->next = NULL; return newNode; } struct Graph* createGraph(int vertices) { struct Graph* graph = malloc(sizeof(struct Graph)); graph->numVertices = vertices; graph->adjLists = malloc(vertices * sizeof(struct Node*)); graph->visited = malloc(vertices * sizeof(int)); int i; for (i = 0; i < vertices; i++) { graph->adjLists[i] = NULL; graph->visited[i] = 0; } return graph; } void addEdge(struct Graph* graph, int src, int dest) { struct Node* newNode = createNode(dest); newNode->next = graph->adjLists[src]; graph->adjLists[src] = newNode; } void DFS(struct Graph* graph, int vertex, int* result, int* index) { struct Node* adjList = graph->adjLists[vertex]; graph->visited[vertex] = 1; while (adjList) { int connectedVertex = adjList->data; if (!graph->visited[connectedVertex]) { DFS(graph, connectedVertex, result, index); } adjList = adjList->next; } result[(*index)++] = vertex; } void topologicalSort(struct Graph* graph) { int* result = malloc(graph->numVertices * sizeof(int)); int index = 0; int i; for (i = 0; i < graph->numVertices; i++) { if (!graph->visited[i]) { DFS(graph, i, result, &index); } } printf("Topological Sort:"); for (i = graph->numVertices - 1; i >= 0; i--) { printf(" %d", result[i]); } printf("\n"); } int main() { int vertices, edges; printf("Enter the number of vertices: "); scanf("%d", &vertices); printf("Enter the number of edges: "); scanf("%d", &edges); struct Graph* graph = createGraph(vertices); int i, src, dest; for (i = 0; i < edges; i++) { printf("Enter edge %d (source destination): ", i+1); scanf("%d %d", &src, &dest); addEdge(graph, src, dest); } topologicalSort(graph); return 0; } ``` 这些代码可以帮助您实现拓扑排序Kahn算法DFS算法。您可以根据需要进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重生之我是cxk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值