1. 程式人生 > >hiho 第215周 Circle Detect(拓撲排序 | DFS)

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

con 技術分享 nbsp 沒有 toposort 過程 oid style 有向圖

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\n"); 45 else printf("YES\n"); 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\n");
44         else printf("NO\n");
45     }
46     return 0;
47 }
View Code

註意:註意對vector存邊的清空。

2.判斷無向圖是否有環

假設無向圖存在n個連通子圖。如果無向圖無環,說明每個連通子圖都是棵樹,即該連通子圖的頂點數(vi)=邊數(ei)+1。

最後得到:V=E+n

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