1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/// 有向グラフの頂点をトポロジカル順に並べて返します。グラフが DAG でなければ None を返します。
///
/// # Examples
/// ```
/// use topological_sort::topological_sort;
///
/// let order = topological_sort(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
/// assert!(order == Some(vec![0, 1, 2, 3]) || order == Some(vec![0, 2, 1, 3]));
/// ```
pub fn topological_sort(n: usize, edges: &[(usize, usize)]) -> Option<Vec<usize>> {
    use std::collections::VecDeque;

    let mut g = vec![vec![]; n];
    let mut in_deg = vec![0; n];
    for &(s, t) in edges {
        g[s].push(t);
        in_deg[t] += 1;
    }

    let mut order = Vec::new();
    let mut que = VecDeque::new();
    #[allow(clippy::needless_range_loop)]
    for s in 0..n {
        if in_deg[s] == 0 {
            order.push(s);
            que.push_back(s);
        }
    }
    while let Some(u) = que.pop_front() {
        for &v in &g[u] {
            in_deg[v] -= 1;
            if in_deg[v] == 0 {
                order.push(v);
                que.push_back(v);
            }
        }
    }
    assert!(order.len() <= n);
    if order.len() == n {
        Some(order)
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use crate::topological_sort;

    #[test]
    fn two_ways() {
        let order = topological_sort(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
        assert!(order == Some(vec![0, 1, 2, 3]) || order == Some(vec![0, 2, 1, 3]));
    }

    #[test]
    fn line() {
        let order = topological_sort(4, &[(0, 1), (1, 2), (2, 3)]);
        assert_eq!(order, Some(vec![0, 1, 2, 3]));
    }

    #[test]
    fn contain_cycle() {
        let order = topological_sort(5, &[(0, 1), (1, 2), (2, 3), (3, 1), (3, 4)]);
        assert_eq!(order, None);
    }
}