拓扑排序

拓扑排序

TODO

补充注释及讲解

Code

邻接表存图

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    static List<Integer>[] adj;
    static int n, m;

    static int[] getInDegree() {
        int[] inDegree = new int[n];
        for (List<Integer> list : adj)
            for (Integer to : list)
                ++inDegree[to];
        return inDegree;
    }

    static boolean topologicalSorting() {
        Stack<Integer> S = new Stack<Integer>();
        int[] inDegree = getInDegree();
        for (int i = 0; i < n; ++i)
            if (inDegree[i] == 0) S.push(i);
        int cnt = 0;
        while (!S.isEmpty()) {
            if (cnt != 0) System.out.print("->");
            System.out.print(S.peek());
            ++cnt;
            for (Integer to : adj[S.pop()])
                if (--inDegree[to] == 0) S.push(to);
        }
        return cnt == n;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        adj = new LinkedList[n];
        for (int i = 0; i < n; ++i) adj[i] = new LinkedList<Integer>();
        for (int i = 0; i < m; ++i) adj[nextInt()].add(nextInt());
        topologicalSorting();
    }
}

链式前向星存图(数组模拟邻接表)

import java.io.*;
import java.util.Stack;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    static int n, m, cnt = 0;
    static int[] head, next, to;

    static void add(int u, int v) {
        next[++cnt] = head[u];
        to[cnt] = v;
        head[u] = cnt;
    }

    static int[] getInDegree() {
        int[] inDegree = new int[n];
        for (int i = 0; i < n; ++i)
            for (int j = head[i]; j != 0; j = next[j])
                ++inDegree[to[j]];
        return inDegree;
    }

    static boolean topologicalSorting() {
        Stack<Integer> S = new Stack<Integer>();
        int[] inDegree = getInDegree();
        for (int i = 0; i < n; ++i)
            if (inDegree[i] == 0) S.push(i);
        int cnt = 0;
        while (!S.isEmpty()) {
            if (cnt != 0) System.out.print("->");
            System.out.print(S.peek());
            ++cnt;
            for (int i = head[S.pop()]; i != 0; i = next[i])
                if (--inDegree[to[i]] == 0) S.push(to[i]);
        }
        return cnt == n;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        head = new int[n];
        next = new int[m + 1];
        to = new int[m + 1];
        for (int i = 0; i < m; ++i) add(nextInt(), nextInt());
        topologicalSorting();
    }
}

测试数据

输入:

13 15
8 7
7 6
6 9
9 10
9 11
9 12
11 12
6 4
0 6
5 4
0 5
0 1
2 0
2 3
3 5

输出:

8->7->2->0->6->9->10->11->12->1->3->5->4

关键路径

Code

import java.io.*;
import java.util.Arrays;
import java.util.Stack;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    static int n, m, cnt = 0;
    static int[] head, next, to, weight;
    //各顶点的事件最早和最晚发生时间
    static int[] ve, vl;

    static void add(int u, int v, int w) {
        next[++cnt] = head[u];
        to[cnt] = v;
        weight[cnt] = w;
        head[u] = cnt;
    }

    static int[] getInDegree() {
        int[] inDegree = new int[n];
        for (int i = 0; i < n; ++i) {
            for (int j = head[i]; j != 0; j = next[j]) {
                ++inDegree[to[j]];
            }
        }
        return inDegree;
    }


    static boolean topologicalSorting(Stack<Integer> T) {
        //S为入度为0的节点的栈
        Stack<Integer> S = new Stack<Integer>();
        int[] inDegree = getInDegree();
        int i, from;
        //从源点出发
        for (i = 0; i < n; ++i)
            if (inDegree[i] == 0) S.push(i);
        while (!S.isEmpty()) {
            from = S.pop();
            T.push(from);
            for (i = head[from]; i != 0; i = next[i]) {
                if (--inDegree[to[i]] == 0) S.push(to[i]);
                //更新该边终点最早开始时间
                if (ve[from] + weight[i] > ve[to[i]]) ve[to[i]] = ve[from] + weight[i];
            }
        }
        //false有环,无拓扑序列
        return T.size() == n;
    }

    static boolean criticalPath() {
        //T为拓扑序列栈
        Stack<Integer> T = new Stack<Integer>();
        //求事件最早发生时间,false有环,无关键路径
        if (!topologicalSorting(T)) return false;
        //从汇点出发,求事件最晚发生时间
        Arrays.fill(vl, ve[n - 1]);
        int from, i;
        while (!T.isEmpty()) {
            from = T.pop();
            for (i = head[from]; i != 0; i = next[i])
                if (vl[from] > vl[to[i]] - weight[i]) vl[from] = vl[to[i]] - weight[i];
        }
        //活动的最早及最晚开始时间(一条边即一个活动)
        System.out.println("关键路径为:");
        for (from = 0; from < n; ++from)
            for (i = head[from]; i != 0; i = next[i])
                if (ve[from] == vl[to[i]] - weight[i])
                    System.out.println(from + "->" + to[i] + ",weight=" + weight[i]);
        return true;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        head = new int[n];
        ve = new int[n];
        vl = new int[n];
        next = new int[m + 1];
        to = new int[m + 1];
        weight = new int[m + 1];
        for (int i = 0; i < m; ++i) add(nextInt(), nextInt(), nextInt());
        criticalPath();
    }
}

测试数据

输入:

6 8
0 1 2
0 2 15
2 1 4
1 3 10
1 4 19
2 4 11
3 5 6
4 5 5

输出:

关键路径为:
0->2,weight=15
1->4,weight=19
2->1,weight=4
4->5,weight=5

参考资料

拓扑排序 - OI Wiki

posted @ 2022-12-21 12:14  Cattle_Horse  阅读(26)  评论(0编辑  收藏  举报