搜索与图论 - 有向图的拓扑序列

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.*;
import java.io.*;

public class Main{
    static int N = 100010;
    static int[] queue = new int[N];
    static int[] h = new int[N];
    static int[] e = new int[N];
    static int[] ne = new int[N];
    static int idx;
    static int[] rd = new int[N];
    static int n;
    
    static void store(int a, int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx ++;
    }
    
    static boolean topSort() {
        int hh = 0, tt = -1;
        
        //将入度为0点加入到队列
        for(int i = 1;i <= n;i ++) {
            if(rd[i] == 0) {
                queue[++ tt] = i;
            }
        }
        
        while(hh <= tt) { //队列不空
            int u = queue[hh ++];
            
            for(int i = h[u];i != -1;i = ne[i]) {
                int j = e[i]; //找到u的一条出边 u->j
                rd[j] --; //删除这条出边
                if(rd[j] == 0) {
                    queue[++ tt] = j;
                }
            }
        }
        return tt == n-1;
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(new InputStreamReader(System.in));
        n = in.nextInt();
        int m = in.nextInt();
        
        for(int i = 0;i < N;i ++) {
            h[i] = -1;
        }
        
        for(int i = 0;i < m;i ++) {
            int a = in.nextInt();
            int b = in.nextInt();
            store(a, b);
            rd[b] ++; //入度加1
        }
        
        //宽度优先搜索
        if(topSort()) {
            for(int i = 0;i < n;i ++) {
                System.out.print(queue[i] + " ");
            }
        }else {
            System.out.println("-1");
        }
        
    }
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值