拓扑排序
拓扑排序
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