附上一个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());
}
}
}
}
}
京公网安备 11010502036488号