hiho 第215周 Circle Detect(拓扑排序 | DFS)

Posted ehanla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hiho 第215周 Circle Detect(拓扑排序 | DFS)相关的知识,希望对你有一定的参考价值。

1.对于判断有向图是否有环

拓扑排序:

拓扑排序原理:

  1. 从DAG(有向无环图)中选一个 没有前驱(即入度为0)的顶点并输出。
  2. 从图中删除该顶点和所有以它为起点的有向边。
  3. 重复1和2直到当前的DAG为空或当前图中不存在无前驱的顶点为止,后一种情况说明有向图中一定有环。

时间复杂度:O(n+e),顶点个数和边的条数。

技术分享图片
 1 //拓扑排序 判断有向图是否有环
 2 #include <queue>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int N=1e5+10;
 9 int in[N];
10 queue <int> Q;
11 int t,n,m,cnt;
12 vector <int> E[N];
13 
14 void toposort(){
15     for(int i=1;i<=n;i++){
16         if(in[i]==0) Q.push(i);
17     }
18     while(!Q.empty()){
19         cnt++;
20         int u=Q.front();
21         Q.pop();
22         for(int i=0;i<E[u].size();i++){
23             int v=E[u][i];
24             in[v]--;
25             if(in[v]==0) Q.push(v);
26         }
27     }
28 }
29 
30 int main(){
31     scanf("%d",&t);
32     while(t--){
33         cnt=0;
34         memset(in,0,sizeof(in));
35         for(int i=1;i<N;i++) E[i].clear();
36         scanf("%d%d",&n,&m);
37         for(int i=1;i<=m;i++){
38             int x,y;
39             scanf("%d%d",&x,&y);
40             E[x].push_back(y);
41             in[y]++;
42         }
43         toposort();
44         if(cnt==n) printf("NO
");
45         else printf("YES
");
46     }
47     return 0;
48 }
View Code

 

DFS:

DFS过程中对点染色:

  1. 还没被DFS访问的点是白色的,初始时所有点都是白色的
  2. 如果点u已经被DFS访问过,但是u的子节点还未全部被访问到,那么把u染成灰色
  3. 如果点u以及u的子节点都被访问过了,从u回溯到u的父节点时,将u染成黑色

如果在DFS的过程中我们沿着有向边到达了一个灰色节点,则说明图中有环;如果从未到达过灰色节点,说明没有环。

时间复杂度:O(n+e),顶点个数和边的条数。

技术分享图片
 1 //DFS 判断有向图是否有环
 2 #include <vector>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 const int N=1e5+10;
10 vector <int> E[N];
11 int f,vis[N];
12 
13 void dfs(int u){
14     if(f) return ;
15     vis[u]=-1;
16     for(int i=0;i<E[u].size();i++){
17         int v=E[u][i];
18         if(vis[v]==0) dfs(v);
19         else if(vis[v]==-1) {f=1;return ;}
20     }
21     vis[u]=1;
22 }
23 
24 int main(){
25     int t,n,m;
26     scanf("%d",&t);
27     while(t--){
28         f=0;
29         memset(vis,0,sizeof(vis));
30         for(int i=1;i<N;i++){
31             E[i].clear();
32         }
33         scanf("%d%d",&n,&m);
34         int a,b;
35         for(int i=1;i<=m;i++){
36             scanf("%d%d",&a,&b);
37             E[a].push_back(b);
38         }
39         for(int i=1;i<=n;i++){
40             if(f) break;
41             if(vis[i]==0) dfs(i);
42         }
43         if(f==1) printf("YES
");
44         else printf("NO
");
45     }
46     return 0;
47 }
View Code

 

注意:注意对vector存边的清空。

 

2.判断无向图是否有环

假设无向图存在n个连通子图。如果无向图无环,说明每个连通子图都是棵树,即该连通子图的顶点数(vi)=边数(ei)+1。

最后得到:V=E+n



以上是关于hiho 第215周 Circle Detect(拓扑排序 | DFS)的主要内容,如果未能解决你的问题,请参考以下文章

hiho一下 第173周

hiho一下 第150周 -- Demo Day (DP)

hiho一下 第174周

hiho 第1周 最长回文子串(manacher)

hiho一下 第172周

hiho 第1周 最长回文子串