简单的回顾了一下拓扑排序,并做了几道题,在此做一下总结。
拓扑排序算法原理比较简单,但在实现上,给我提供了一种比较好用的技巧。
对这种需要判断环的存在的,需要区分历史遍历过的和现在正在遍历的。这里对 v i s [ ] vis[] vis[]进行了扩展,用 − 1 -1 −1来表示标记现在正在访问的路径,而访问结束标记为 1 1 1。当然,这个只能在 d f s dfs dfs中使用。
bool dfs(int node){
vis[node]=-1;
For(i,0,G[node].size()-1){
int u=G[node][i];
if(vis[u]==-1) return 0;
if(vis[u]==1) continue;
--deg[u];
if(!deg[u]) if(dfs(u)==0) return 0;
}
vis[node]=1;
return 1;
}
当然,用堆或者队列之类的也是可以进行维护的。不过对于判断是否有环的话,还是 d f s dfs dfs更适合。
下面来说一说具体的题目:
H i h o c o d e r 1174 Hihocoder1174 Hihocoder1174:模板题、
H i h o c o d e r 1175 Hihocoder1175 Hihocoder1175:在拓扑排序时,顺便递推一下,也比较简单。
U V A UVA UVA 437 437 437:这一题是要先构造出图来,然后DAG图上dp。主要难点在于想出构造图。当时刚刚看到这道题时,还是有点懵逼的。这类不好直接处理关系的题,可以考虑预处理一下关系,通过转化到图上(或其他类型的结构),再进行处理。
H D U 4857 HDU4857 HDU4857:这题挺坑的,输出要求是保证顺序条件的同时,依次保证 1 1 1, 2 2 2, 3..... 3..... 3.....在前,而不是字典序的大小。最开始处理的时候,总是不自觉的处理成字典序了。但是字典序的处理提供了一个想法,字典序的处理是尽量保证小的在前,而如果要是 1 1 1, 2 2 2, 3..... 3..... 3.....在前,即保证大的尽量在后面,这也就是反向构图,保证大的尽量在前面,然后再倒序输出。
C o d e f o r c e s 770 C Codeforces 770C Codeforces770C:这题的难度不大,可以考虑先反向构图,从每个被选中点去遍历,找出一个DAG图。然后在DAG图上拓扑排序得到答案。坑点在于判断无解的情况,最开始无解的情况在 v i s = 1 vis=1 vis=1时,继续进行了 d f s dfs dfs,导致 d e g deg deg出了问题,最后使整个过程都出了点问题。