1.小朋友崇拜圈
最开始,题主使用dfs实现拓扑排序,但是最后发现自己无法在遍历过程中记录每个节点(小朋友)的出度,导致后续找找最大环时不能确定函数的入口(题主太菜,找不到有效的方法)。该实现方法pass!
后面临时恶补使用bfs,利用Queue(队列)的方法实现拓扑排序,最后成功将此题解决。
输入:
9 3 4 2 5 3 8 4 6 9
输出:
4
1.1思路分析
首先思考,怎么确定哪几个元素组成环?总不能手画把(手动滑稽)
由题可知,所谓小朋友崇拜圈抽象看就是一个有向有环图,环可以类比为一个首尾咬住的贪吃蛇,蛇身上的每一个节点都指向下一个节点,最终,我们的指针从头开始遍历到尾,最后又会和头相遇——这就是环。在环中,每一个节点的入度都为1,那么我们可以使用拓扑排序得到所有入度为1的点,我们要找的最大环,就在里面。
怎么找最大环?搜索!dfs搜到底就完了,递归的退出条件就是当首位相等(表示把当前环走完了一遍)。
1.2代码
1.2.1基于bfs的拓扑排序
List<Integer>[] graph=buildGraph();//邻接表int[] indegree=new int[N];int[] res=new int[N];//拓扑排序结果Queue<Integer> q=new LinkedList<>();for(int i=0;i<indegree.length;i++){if(indegree[i]==0){q.offer(i);}}int count=0;while(!q.isEmpty()){int cur=q.poll();res[count]=cur;count++;for(int next:graph){//由于该点被移除,那么该点的下一节点的入读都要减1indegree[next]--;if(indegree[next]==0){q.offer(next);}}}return res;//res中就是拓扑排序的结果
1.2.2基于dfs的拓扑排序
List<Integer>[] graph=buildGraph;List<Integer> Path=new LinkedList<>();boolean[] vis=new boolean[N];//记录是否重复遍历boolean[] onPath=new boolean[N];//记录堆栈的遍历情况,有重复说明有环void main(){for(int i=0;i<N;i++){dfs(vis,graph,i);}Collections.reverse(Path);//后序遍历反转的结果就是拓扑排序}void dfs(boolean[] vis,List<Integer>[] graph,int start){if(vis[start]){return;}vis[start]=true;onPath[start]=true;for(int next:graph[start]){dfs(vis,graph,next);}Path.add(start);vis[start]=false;}
1.2.3完整代码
package lanqiao;import java.util.LinkedList;import java.util.List;import java.util.Queue;import java.util.Scanner;public class Main2 {static int max = 0;static int circle = 1;public static void main(String[] args) {// TODO Auto-generated method stubScanner scan = new Scanner(System.in);int N = scan.nextInt();int[] indegree = new int[N + 1];int[] res = new int[N];// 拓扑排序结果int[] arr = new int[N + 1];boolean[] vis = new boolean[N + 1];List<Integer>[] list = new LinkedList[N + 1];scan.nextLine();for (int i = 1; i <= N; i++) {int tmp = scan.nextInt();arr[i] = tmp;indegree[arr[i]]++;}for (int i = 1; i < list.length; i++) {list[i] = new LinkedList<Integer>();list[i].add(arr[i]);}Queue<Integer> q = new LinkedList<Integer>();for (int i = 1; i < indegree.length; i++) {if (indegree[i] == 0) {q.offer(i);}}int count = 0;while (!q.isEmpty()) {int tmp = q.poll();res[count] = tmp;count++;for (int next : list[tmp]) {indegree[next]--;if (indegree[next] == 0) {q.offer(next);}}}//dfs寻找最大环for (int s = 1; s < arr.length; s++) {if (indegree[s] != 0) {circle = 1;// vis[s] = true;dfs(arr, s, arr[s]);}}System.out.println(max);// for (int j = 1; j < indegree.length; j++) {// System.out.print(indegree[j] + " ");// } // indegree数组 中入度为0的即表示不在环中0 1 1 1 1 1 0 1 1// // 1 7不在环中}public static void dfs(int[] arr, int now, int next) {if (next == now) {max = Math.max(max, circle);return;}circle++;dfs(arr, now, arr[next]);}}
