解题思路

  1. 构建图

    • 使用邻接表存储图
    • 记录每个节点的入度
  2. Kahn算法

    • 将所有入度为 的节点加入队列
    • 每次从队列取出一个节点,将其加入结果
    • 减少其所有邻接节点的入度
    • 如果邻接节点入度变为 ,则加入队列
  3. 检查有效性

    • 如果最终结果数组长度不等于 ,说明图中有环
    • 否则得到的就是一个有效的拓扑序

代码

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

class Solution {
public:
    vector<int> topoSort(int n, int m) {
        vector<vector<int>> adj(n + 1);  // 邻接表
        vector<int> inDegree(n + 1, 0);  // 入度数组
        vector<int> result;  // 结果数组
        
        // 读取边并构建图
        for(int i = 0; i < m; i++) {
            int u, v;
            cin >> u >> v;
            adj[u].push_back(v);
            inDegree[v]++;
        }
        
        // 将所有入度为0的节点加入队列
        queue<int> q;
        for(int i = 1; i <= n; i++) {
            if(inDegree[i] == 0) {
                q.push(i);
            }
        }
        
        // BFS
        while(!q.empty()) {
            int curr = q.front();
            q.pop();
            result.push_back(curr);
            
            for(int next : adj[curr]) {
                inDegree[next]--;
                if(inDegree[next] == 0) {
                    q.push(next);
                }
            }
        }
        
        // 检查是否有环
        if(result.size() != n) {
            return vector<int>{-1};
        }
        
        return result;
    }
};

int main() {
    int n, m;
    cin >> n >> m;
    
    Solution sol;
    vector<int> result = sol.topoSort(n, m);
    
    // 输出结果
    if(result[0] == -1) {
        cout << -1;
    } else {
        for(int i = 0; i < result.size(); i++) {
            cout << result[i];
            if(i != result.size() - 1) cout << " ";
        }
    }
    
    return 0;
}
import java.util.*;
import java.io.*;

public class Main {
    public static void topoSort(int n, int m) throws IOException {
        // 使用BufferedReader加快输入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        
        // 使用数组存储边
        int[][] edges = new int[m][2];
        int[] inDegree = new int[n + 1];
        ArrayList<Integer>[] adj = new ArrayList[n + 1];
        
        // 初始化邻接表
        for(int i = 1; i <= n; i++) {
            adj[i] = new ArrayList<>();
        }
        
        // 读取边并构建图
        for(int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            adj[u].add(v);
            inDegree[v]++;
        }
        
        // 将所有入度为0的节点加入队列
        Queue<Integer> q = new LinkedList<>();
        for(int i = 1; i <= n; i++) {
            if(inDegree[i] == 0) {
                q.offer(i);
            }
        }
        
        // 使用StringBuilder存储结果
        StringBuilder result = new StringBuilder();
        int count = 0;
        
        // BFS
        while(!q.isEmpty()) {
            int curr = q.poll();
            result.append(curr).append(" ");
            count++;
            
            for(int next : adj[curr]) {
                inDegree[next]--;
                if(inDegree[next] == 0) {
                    q.offer(next);
                }
            }
        }
        
        // 输出结果
        if(count != n) {
            System.out.print(-1);
        } else {
            // 删除最后一个空格
            System.out.print(result.substring(0, result.length() - 1));
        }
    }
    
    public static void main(String[] args) throws IOException {
        topoSort(0, 0);
    }
}
from collections import defaultdict, deque

def topoSort(n, m):
    # 构建邻接表和入度数组
    adj = defaultdict(list)
    inDegree = [0] * (n + 1)
    
    # 读取边并构建图
    for _ in range(m):
        u, v = map(int, input().split())
        adj[u].append(v)
        inDegree[v] += 1
    
    # 将所有入度为0的节点加入队列
    q = deque()
    for i in range(1, n + 1):
        if inDegree[i] == 0:
            q.append(i)
    
    result = []
    # BFS
    while q:
        curr = q.popleft()
        result.append(curr)
        
        for next_node in adj[curr]:
            inDegree[next_node] -= 1
            if inDegree[next_node] == 0:
                q.append(next_node)
    
    # 检查是否有环
    if len(result) != n:
        return [-1]
    
    return result

# 读取输入
n, m = map(int, input().split())
result = topoSort(n, m)

# 输出结果
if result[0] == -1:
    print(-1)
else:
    print(*result)

算法及复杂度分析

  • 算法 算法

  • 时间复杂度

    • 是节点数, 是边数
    • 每个节点和边都只会被访问一次
  • 空间复杂度

    • 需要存储邻接表和入度数组

注意事项

  1. 需要处理图中有环的情况
  2. 拓扑序可能不唯一,输出任意一个合法序列即可