1.小朋友崇拜圈

最开始,题主使用dfs实现拓扑排序,但是最后发现自己无法在遍历过程中记录每个节点(小朋友)的出度,导致后续找找最大环时不能确定函数的入口(题主太菜,找不到有效的方法)。该实现方法pass!
后面临时恶补使用bfs,利用Queue(队列)的方法实现拓扑排序,最后成功将此题解决。
image.png
输入:

9 3 4 2 5 3 8 4 6 9

输出:

4

1.1思路分析

首先思考,怎么确定哪几个元素组成环?总不能手画把(手动滑稽)
由题可知,所谓小朋友崇拜圈抽象看就是一个有向有环图,环可以类比为一个首尾咬住的贪吃蛇,蛇身上的每一个节点都指向下一个节点,最终,我们的指针从头开始遍历到尾,最后又会和头相遇——这就是环。在环中,每一个节点的入度都为1,那么我们可以使用拓扑排序得到所有入度为1的点,我们要找的最大环,就在里面。
怎么找最大环?搜索!dfs搜到底就完了,递归的退出条件就是当首位相等(表示把当前环走完了一遍)。

1.2代码

1.2.1基于bfs的拓扑排序

  1. List<Integer>[] graph=buildGraph();//邻接表
  2. int[] indegree=new int[N];
  3. int[] res=new int[N];//拓扑排序结果
  4. Queue<Integer> q=new LinkedList<>();
  5. for(int i=0;i<indegree.length;i++){
  6. if(indegree[i]==0){
  7. q.offer(i);
  8. }
  9. }
  10. int count=0;
  11. while(!q.isEmpty()){
  12. int cur=q.poll();
  13. res[count]=cur;
  14. count++;
  15. for(int next:graph){
  16. //由于该点被移除,那么该点的下一节点的入读都要减1
  17. indegree[next]--;
  18. if(indegree[next]==0){
  19. q.offer(next);
  20. }
  21. }
  22. }
  23. return res;//res中就是拓扑排序的结果

1.2.2基于dfs的拓扑排序

  1. List<Integer>[] graph=buildGraph;
  2. List<Integer> Path=new LinkedList<>();
  3. boolean[] vis=new boolean[N];//记录是否重复遍历
  4. boolean[] onPath=new boolean[N];//记录堆栈的遍历情况,有重复说明有环
  5. void main(){
  6. for(int i=0;i<N;i++){
  7. dfs(vis,graph,i);
  8. }
  9. Collections.reverse(Path);//后序遍历反转的结果就是拓扑排序
  10. }
  11. void dfs(boolean[] vis,List<Integer>[] graph,int start){
  12. if(vis[start]){
  13. return;
  14. }
  15. vis[start]=true;
  16. onPath[start]=true;
  17. for(int next:graph[start]){
  18. dfs(vis,graph,next);
  19. }
  20. Path.add(start);
  21. vis[start]=false;
  22. }

1.2.3完整代码

  1. package lanqiao;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Queue;
  5. import java.util.Scanner;
  6. public class Main2 {
  7. static int max = 0;
  8. static int circle = 1;
  9. public static void main(String[] args) {
  10. // TODO Auto-generated method stub
  11. Scanner scan = new Scanner(System.in);
  12. int N = scan.nextInt();
  13. int[] indegree = new int[N + 1];
  14. int[] res = new int[N];// 拓扑排序结果
  15. int[] arr = new int[N + 1];
  16. boolean[] vis = new boolean[N + 1];
  17. List<Integer>[] list = new LinkedList[N + 1];
  18. scan.nextLine();
  19. for (int i = 1; i <= N; i++) {
  20. int tmp = scan.nextInt();
  21. arr[i] = tmp;
  22. indegree[arr[i]]++;
  23. }
  24. for (int i = 1; i < list.length; i++) {
  25. list[i] = new LinkedList<Integer>();
  26. list[i].add(arr[i]);
  27. }
  28. Queue<Integer> q = new LinkedList<Integer>();
  29. for (int i = 1; i < indegree.length; i++) {
  30. if (indegree[i] == 0) {
  31. q.offer(i);
  32. }
  33. }
  34. int count = 0;
  35. while (!q.isEmpty()) {
  36. int tmp = q.poll();
  37. res[count] = tmp;
  38. count++;
  39. for (int next : list[tmp]) {
  40. indegree[next]--;
  41. if (indegree[next] == 0) {
  42. q.offer(next);
  43. }
  44. }
  45. }
  46. //dfs寻找最大环
  47. for (int s = 1; s < arr.length; s++) {
  48. if (indegree[s] != 0) {
  49. circle = 1;
  50. // vis[s] = true;
  51. dfs(arr, s, arr[s]);
  52. }
  53. }
  54. System.out.println(max);
  55. // for (int j = 1; j < indegree.length; j++) {
  56. // System.out.print(indegree[j] + " ");
  57. // } // indegree数组 中入度为0的即表示不在环中0 1 1 1 1 1 0 1 1
  58. // // 1 7不在环中
  59. }
  60. public static void dfs(int[] arr, int now, int next) {
  61. if (next == now) {
  62. max = Math.max(max, circle);
  63. return;
  64. }
  65. circle++;
  66. dfs(arr, now, arr[next]);
  67. }
  68. }