邻接表

形如1一>3这样的式子是推导式,说明结论1可以推导出结论了。
显然这样的推导式具有传递性:
如果1一>33一>5,那么肯定满足1一>5
现在给出n个推导式,你需要输出结论C能够推导出多少个不同的结论。
显然任何结论都可以推导出自己。

输入描述:
第一行输入两个整数n和c,含义如题意所述。
接下来n行,每行输入两个整数x,y,表示一个推导式x->y,可能会出现重复的推导式。
(1 <= n <= 10^5),(1 <= x,y,c <= 10000)
输出描述:
输出一个整数,表示结论c能推导出的不同结论的数目。

示例1:
输入:
5 1
1 2
1 3
3 9
4 2
8 1
输出:
4
说明:
根据推导式1一>2,1一>3,3一>9,可以判断出结论1可以推出结论2,3,9,加上本身总共4个结论。

代码实现

算法思路:

  1. 建立哈希表edges,记录每个数字所能推导的结论。
  2. 建立队列que,记录起始结论以及后续推导出的结论。
  3. 建立HashSet集合res,记录最终答案。
  4. 建立哈希表,去除重复,以防循环推导。
import java.util.*;

public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int c = sc.nextInt();
HashMap<Integer, HashSet<Integer>> edges = new HashMap<>();
for(int i = 0; i < n; i++){
int a = sc.nextInt(), b = sc.nextInt();
if(!edges.containsKey(a)){
HashSet<Integer> set = new HashSet<>(); //如果key没记录过,则新建set添加
set.add(b);
edges.put(a, set);
}else{
if(!edges.get(a).contains(b)){
edges.get(a).add(b); //若key记录过,则直接添加
}
}
}
Queue<Integer> que = new ArrayDeque<>();
que.add(c);
HashSet<Integer> res = new HashSet<>();
res.add(c);
HashMap<Integer, Integer> map = new HashMap<>();
while(!que.isEmpty()){
int curr = que.peek(); //记录当前结论
que.poll(); //将当前结论出队列
map.put(curr, map.getOrDefault(curr, 0) + 1); //记录次数
if(map.get(curr) != 1)continue; //如果不是第一次用,则跳出本次循环
if(!edges.containsKey(curr))continue; //如果该结论没有推导结论,则跳出本次循环
for(int i: edges.get(curr)){ //将一个结论的所有可推导出的结论加进que和res
res.add(i);
que.add(i);
}
}
System.out.println(res.size());
}
}

参考

jiankychen教你学算法 - 学算法,看我就够了