• 数据结构与算法


    目录

    拓扑排序

    题目 有向图的拓扑排序

    解题思路

    Java代码

    树的 广度优先遍历

    题目 树中点的层次

    思路

    核心代码

    代码


    拓扑排序


    含义:

    一个有向图,如果图中有入度为 0 的点,就把这个点删掉,同时也删掉这个点所连的边。

    一直进行上面出处理,如果所有点都能被删掉,则这个图可以进行拓扑排序

    题目 有向图的拓扑排序

    给定一个 nn 个点 mm 条边的有向图,点的编号是 11 到 nn,图中可能存在重边和自环。

    请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1−1。

    若一个由图中所有点构成的序列 AA 满足:对于图中的每条边 (x,y)(x,y),xx 在 AA 中都出现在 yy 之前,则称 AA 是该图的一个拓扑序列。

    输入格式

    第一行包含两个整数 nn 和 mm。

    接下来 mm 行,每行包含两个整数 xx 和 yy,表示存在一条从点 xx 到点 yy 的有向边 (x,y)(x,y)。

    输出格式

    共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

    否则输出 −1−1。

    数据范围

    1≤n,m≤105

    解题思路

    首先记录各个点的入度

    然后将入度为 0 的点放入队列

    将队列里的点依次出队列,然后找出所有出队列这个点发出的边,删除边,同事边的另一侧的点的入度 -1。

    如果所有点都进过队列,则可以拓扑排序,输出所有顶点。否则输出-1,代表不可以进行拓扑排序。

    Java代码

    1. import java.util.Scanner;
    2. import java.util.Queue;
    3. import java.util.LinkedList;
    4. public class Main{
    5. static int N = 100010;
    6. static int[] h = new int[N]; //以第一个节点的编号为索引,存储所有单链表的头节点
    7. static int[] e = new int[N]; //以当前要操作的节点为索引,存储第二个节点的编号
    8. static int[] ne = new int[N]; //以当前操作的节点为索引,存储下一个节点
    9. static int[] d = new int[N]; //存储i号节点的入度
    10. static int[] top = new int[N];
    11. static Queue q = new LinkedList<>();
    12. static int idx,n,cnt = 1; //cnt指的是top中有多少元素
    13. public static void main(String[] args){
    14. Scanner in = new Scanner(System.in);
    15. n = in.nextInt();
    16. int m = in.nextInt();
    17. for(int i = 0; i < N; i ++) h[i] = -1;
    18. for(int i = 0; i < m; i ++)
    19. {
    20. int a = in.nextInt();
    21. int b = in.nextInt();
    22. add(a,b);
    23. d[b]++; //入度+1
    24. }
    25. if(topsort())
    26. {
    27. for(int i = 1; i <= n; i ++) System.out.print(top[i] + " ");
    28. }
    29. else System.out.print("-1");
    30. }
    31. private static void add(int a ,int b)
    32. {
    33. e[idx] = b;
    34. ne[idx] = h[a];
    35. h[a] = idx++;
    36. }
    37. private static boolean topsort()
    38. {
    39. for(int i = 1; i <= n; i ++) //因为是从1开始编号的,所以从1开始遍历
    40. {
    41. if(d[i] == 0) q.offer(i); //遍历每个节点,入度为0就入栈
    42. }
    43. while(q.size() != 0)
    44. {
    45. int t = q.poll();
    46. top[cnt] = t;
    47. cnt++;
    48. for(int i =h[t]; i != -1; i = ne[i]) //遍历链表,删除1的所有出度
    49. {
    50. int j = e[i]; //j找到第一个节点指向的点b
    51. if(--d[j] == 0) q.offer(j); //删除边
    52. }
    53. }
    54. return cnt >= n; //注意这里一定是>=,因为cnt = 3以后会++等于4
    55. }
    56. }

    树的 广度优先遍历

    题目 树中点的层次

    给定一个 nn 个点 mm 条边的有向图,图中可能存在重边和自环。

    所有边的长度都是 11,点的编号为 1∼n1∼n。

    请你求出 11 号点到 nn 号点的最短距离,如果从 11 号点无法走到 nn 号点,输出 −1−1。

    输入格式

    第一行包含两个整数 nn 和 mm。

    接下来 mm 行,每行包含两个整数 aa 和 bb,表示存在一条从 aa 走到 bb 的长度为 11 的边。

    输出格式

    输出一个整数,表示 11 号点到 nn 号点的最短距离。

    思路

    用 dist 数组保存1号节点到各个节点的距离,初始时,都是无穷大。

    用 st 数组标记各个节点有没有走到过。

    从 1 号节点开始,广度优先遍历:

    1 号节点入队列,dist[1] 的值更新为 0。

    如果队列非空,就取出队头,找到队头节点能到的所有节点。如果队头节点能到走到的节点没有标记过,就将节点的dist值更新为队头的dist值+1,然后入队。

    重复步骤 2 直到队列为空。

    这个时候,dist数组中就存储了 1 号节点到各个节点的距离了。如果距离是无穷大,则不能到达,输出 -1,如果距离不是无穷大,则能到达,输出距离。

    核心代码

    1. for (int i = h[t]; i != -1; i = ne[i]) // ne[i]上的点都是与i节点距离为1的点
    2. {
    3. int j = e[i]; // 向外走一步
    4. if (d[j] == -1) // 如果j没有被遍历过
    5. {
    6. d[j] = d[t] + 1; // 因为路径长度都是1,所以直接在上一步的基础上加上1即可
    7. q.push(j); // 将j加到队列中
    8. }
    9. }

    代码

    1. import java.util.Scanner;
    2. import java.util.Queue;
    3. import java.util.LinkedList;
    4. public class Main{
    5. static int N = 100010;
    6. static int[] h = new int[N];
    7. static int[] e = new int[N];
    8. static int[] ne = new int[N];
    9. static int[] d = new int[N]; //储存每个节点距离起点的距离
    10. static Queue q = new LinkedList<>();
    11. static boolean[] st = new boolean[N];
    12. static int idx,n;
    13. public static void main(String[] args){
    14. Scanner in = new Scanner(System.in);
    15. n = in.nextInt();
    16. int m = in.nextInt();
    17. for(int i = 0; i < N; i ++)
    18. {
    19. h[i] = -1;
    20. d[i] = -1;
    21. }
    22. for(int i = 0; i < m; i ++)
    23. {
    24. int a = in.nextInt();
    25. int b = in.nextInt();
    26. add(a,b);
    27. }
    28. System.out.print(bfs(1)); //求的是1-n的最短距离,从1开始搜就可以了
    29. }
    30. private static void add(int a, int b)
    31. {
    32. e[idx] = b;
    33. ne[idx] = h[a];
    34. h[a] = idx++;
    35. }
    36. private static int bfs(int u)
    37. {
    38. q.offer(u);
    39. d[1] = 0; //自己距离自己为0,在这里的作用相当于表示走过了
    40. while(q.size() != 0)
    41. {
    42. int t = q.poll();
    43. for(int i = h[t]; i != -1; i = ne[i])
    44. {
    45. int j = e[i]; //j相当于当前节点的子节点,因为当前节点会不满足条件直接跳出循环
    46. if(d[j] == -1)
    47. {
    48. q.offer(j);
    49. d[j] = d[t] + 1;
    50. }
    51. }
    52. }
    53. return d[n];
    54. }
    55. }

     

  • 相关阅读:
    CSDN上代码块背景颜色的设置
    Web3行业人才需求激增,加密初创企业的薪资究竟如何?
    人不可貌相!伴娘头发稀少被嘲,新娘:我闺蜜是程序员年薪50万
    云主机内网通信ping不通问题处理过程
    计算机毕业设计 基于微信小程序的“共享书角”图书借还管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
    php://input、php://output 区别及用法
    Python CNN卷积神经网络实例讲解,CNN实战,CNN代码实例,超实用
    SpringBoot:Put和Delete请求(动力)
    对网络流的一个小总结
    C语言源代码系列-管理系统之会员计费系统
  • 原文地址:https://blog.csdn.net/m0_66057675/article/details/125991838