1.题目
给定一个n个点m条边的有向图,点的编号是1到n,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。
若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。
输入格式
第一行包含两个整数n和m
接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。
输出格式
共一行,如果存在拓扑序列,则输出拓扑序列。
否则输出-1。
数据范围
1≤n,m≤1051≤n,m≤105
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
2、分析
拓扑排序
只适用于 AOV网 (有向无环图)
算法流程:
用队列来执行 ,初始化讲所有入度为0的顶点入队。
主要由一下两步循环执行,直到不存在入度为 0 的顶点为止:
选择一个入度为 0 的顶点,并将它输出;
删除图中从顶点连出的所有边。
循环结束,若输出的顶点数小于图中的顶点数,则表示该图存在回路,即无法拓扑排序;否则,输出的就是拓扑序列 (不唯一)
3.代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Code_0708_Tuopu {
//图拓扑排序
static int n;
static int N = 100010;
//h是代表头节点
static int[] h = new int[N];
//存储的值
static int[] e = new int[N];
//下一个的索引
static int[] ne = new int[N];
static int idx;
//入度
static int[] d = new int[N];
//树和图都是这么做的!
//将b插到a的后面
static void add(int a , int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
// 以u为根的子树中,点的数量
static boolean tuopu(){
Queue<Integer> queue = new LinkedList();
//找到入度为0的点
for (int i = 1;i <= n;i++){
if (d[i] == 0){
queue.add(0);
}
}
//计算进队列的数量
int res = 0;
while (!queue.isEmpty()){
int t = queue.poll();
for (int i = h[t]; i != -1;i = ne[i]){
int j = e[i];
d[j]--;
if (d[j] == 0){
queue.add(j);
res++;
}
}
}
//判断是否进了n个点
return res == n - 1;
}
public static void main(String[] agrs){
//把里面的值都赋值成-1
//init
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int x : h){
x = - 1;
}
for (int i = 0;i < n - 1;i++){
int a, b;
a = sc.nextInt();
b = sc.nextInt();
add(a,b);
d[b]++;
}
if (tuopu()){
System.out.println("true");
}else {
System.out.println(-1);
}
System.out.println(tuopu());
}
}