b_aw_可达性统计(拓扑排序+bitset)

N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量(1≤N,M≤30000)

topo排序:图G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
有了topo序,则可以利用倒序遍历topo序来优化算法,因为path[i-1]在DAU中出现path[i]之前,所以先更新后面的结点的可达结点

import java.util.*;
import java.io.*;
class Solution {
    int n,m,in[],path[],k;
    List<Integer> g[];
    BitSet f[];
    boolean vis[];
    void topo() {
        Queue<Integer> q=new LinkedList<>();
        for (int i=1; i<=n; i++) if (in[i]==0)
            q.add(i);
        while (!q.isEmpty()) {
            int u=q.poll();
            path[k++]=u;
            for (int v : g[u]) if (--in[v]==0) {
                q.add(v);
            }
        }
    }
    void init() throws IOException {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        n=sc.nextInt(); m=sc.nextInt(); in=new int[n+1]; vis=new boolean[n+1];
        g=new ArrayList[n+1]; f=new BitSet[n+1]; path=new int[n+1];
        for (int i=1; i<=n; i++) {
            g[i]=new ArrayList<>();
            f[i]=new BitSet();
        }
        for (int i=0; i<m; i++) {
            int u=sc.nextInt(), v=sc.nextInt();
            g[u].add(v); in[v]++;
        }
        topo(); //topo序就是一条有向的相邻结点可达的路径
        for (int i=k-1; i>=0; i--) { //从后往前遍历topo序上的点
            int u=path[i]; //u的后继结点v能到的点,u也能到达
            f[u].set(u); //自己能到达自己
            for (int v : g[u]) {
                f[u].or(f[v]);
            }
        }
        for (int i=1; i<=n; i++) System.out.println(f[i].cardinality());
    }
}
public class Main{
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
        s.init();
    }
}
posted @ 2020-10-29 22:27  童年の波鞋  阅读(85)  评论(0编辑  收藏  举报