并查集、拓扑排序

315 阅读1分钟

做题小技巧:

  • 无向图连通性 考虑 并查集
  • 有向图依赖性 考虑 深度广度优先 拓扑排序

并查集(684、839\547、684、685)

  • 完整实现
public class DSU {
     private int count; //记录连通分量
     private int[]parent; //节点x的根节点是parent[x]
     public DSU(int n){
         //一开始互不相通
         this.count=n;
         //一开始,每个节点是自己的父节点
         parent=new int[n];
         for (int i = 0; i <n ; i++) {
             parent[i]=i;
         }
     }
      /*
      将p和q连接, 如果两个节点被连通,那么则让其中的一个根节点连接到另一个节点的根节点上
      */
     public void union(int p,int q){
         int rootP=find(p);
         int rootQ=find(q);
         if(rootP==rootQ){
             return;
         }
         //将两颗树合并为一颗
         parent[rootP]=rootQ; //parent[rootQ]=rootP 效果是一样的
         count--; //两个分量合二为一
     }
     //返回某个节点x的根节点
     private int find(int x){
          //根节点的parent[x]==x
          while (parent[x]!=x){
              x=parent[x];
          }
          return x;
     }
     /*
      判断p和q是否连通:如果两个节点是连通的,那么他们一定拥有相同的根节点
      */
     public boolean connected(int p,int q){
         int rootP=find(p);
         int rootQ=find(q);
         return rootP==rootQ;
     }
     /*
     返回具体有多少个连通分量
      */
      public int count(){
         return count;
      }
}

拓扑排序(判断是否是 有向无环图(DAG))399、207、210

//入度表
        int[] indegrees=new int[n];
        List<List<Integer>> adjacency=new ArrayList<>();
        for(int i=0;i<numCourses;i++){
            adjacency.add(new ArrayList<>());
        }
        //构建领接表
        for(int[] cp:prerequisites){
            indegrees[cp[0]]++;
            adjacency.get(cp[1]).add(cp[0]);
        }
        //记录入度为0的点
        LinkedList<Integer> queue=new LinkedList<>();
        for(int i=0;i<n;i++) if(indegrees[i]==0) queue.add(i);
        //BFS
        while(!queue.isEmpty()){
            int pre=queue.poll();
            n--;
            for(int cur:adjacency.get(pre)){
                if(--indegrees[cur]==0) queue.add(cur);
            }
        }
        return n==0;