- 问题本质:有向无环图的宽度优先遍历。
- 本质:拓扑图的最短路 就是 最熟悉的DP。
- 规定:每条边都是从起点指向终点。无逆序。
- 算法思路:
- 入度为0的点全部作为起点.
- 一个入读数组d[];入度数组在加边的时候初始化。
- 遍历d数组,if(d[i]==0)那么这个点入队。
- 然后bfs。
- 队列里的次序就是拓扑排序。
- 拓扑排序 不唯一。
-
static void bfs(){ for(int i= 1;i<=N;i++) if(d[i]==0) Q[++tt] = i; //把入度为0 的真正的值存进去。 while(hh<=tt){ //队列不空 int u = Q[hh++]; for(int i = h[u];i!=-1;i=NE[i]){ int j = E[i]; d[j]--; if(d[j]==0) Q[++tt] = j; } } if(tt == N-1) { //所有的点都已经入队过了。 模拟队列可以直接记录拓扑排序 for(int i =0;i<N;i++) System.out.print(Q[i]+" "); }else System.out.println(-1); }
题:
- 课程表:学习A课程前必须学习B课程,问是否可能完成。 (easy)
- 可达性分析:问每个点能到达多少个点。 正向超时,反向拓扑排序+bitset (mid)
//初始化bitset for(int i = 1;i<=N;i++){ bitSets[i] = new BitSet(); //不需要设置长度吗??? bitSets[i].set(i); //把第i位置为1; } for(int k = top.size()-1;k>=0;k--){ // 倒叙找能到达的点,像是DP回溯 int t = top.get(k); for(int i = h[t];i!=-1;i=NE[i]){ int j = E[i]; bitSets[t].or(bitSets[j]); } } for(int i = 1;i<=N;i++) System.out.println(bitSets[i].cardinality());
- vivo编译依赖问题:因为要保证顺序的拓扑排序,使用优先队列代替模拟队列即可,单独开一个list top 记录拓扑排序。 (mid)