附上一个java的通过的解法:也是使用拓扑排序+BitSet。
思路如下,利用HashMap建立邻接表,表里存放节点和出度邻居,然后建立入度表用来记录各个定点的入度,作用是在拓扑排序中寻找入度为0的顶点,因为前驱的可达点是其所有后继的可达点并集,那么如果先计算出后继的可达点,那么可以大大提高效率,这里就需要输出拓扑排序序列,然后逆序遍历该序列,遍历中利用BitSet的二进制表示来设置一个点的可达点,然后利用BitSet的or函数将前驱的位集与后继的位集求并集就可以得出该前驱的位集。最后输出位集的结果就行,需要注意的是节点是从1开始编号的,所以建立位集范围是0到N,但是输出的是1到N。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNextInt()) { int n = sc.nextInt(); int m = sc.nextInt(); Map<Integer, List<Integer>> map = new HashMap<>(); Map<Integer, Integer> indgree = new HashMap<>(); for (int i = 0; i < m; ++i) { int node = sc.nextInt(); if (!map.containsKey(node)) { map.put(node, new ArrayList<>()); } int v_node = sc.nextInt(); if (!map.get(node).contains(v_node)) { map.get(node).add(v_node); indgree.put(node, indgree.getOrDefault(node, 0)); indgree.put(v_node, indgree.getOrDefault(v_node, 0) + 1); } } List<Integer> topList = new ArrayList<>(); Queue<Integer> queue = new LinkedList<>(); for (int key : indgree.keySet()) { if (indgree.get(key) == 0) { queue.offer(key); } } while (!queue.isEmpty()) { int node = queue.poll(); topList.add(node); if (map.containsKey(node)) { for (int v : map.get(node)) { int val = indgree.get(v) - 1; indgree.put(v, val); if (val == 0) { queue.offer(v); } } } } BitSet[] bitSets = new BitSet[n + 1]; for (int i = 0; i < n + 1; ++i) { bitSets[i] = new BitSet(); } for (int i = topList.size() - 1; i >= 0; --i) { int p = topList.get(i); bitSets[p].set(p); if (map.containsKey(p)) { for (int v : map.get(p)) { bitSets[p].or(bitSets[v]); } } } for (int i = 1; i <= n; ++i) { if (bitSets[i].cardinality() == 0) { System.out.println(1); } else { System.out.println(bitSets[i].cardinality()); } } } } }