hiho 第215周 Circle Detect(拓撲排序 | DFS)
阿新 • • 發佈:2018-08-17
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> 6View Codeusing 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 }
DFS:
DFS過程中對點染色:
- 還沒被DFS訪問的點是白色的,初始時所有點都是白色的
- 如果點u已經被DFS訪問過,但是u的子節點還未全部被訪問到,那麽把u染成灰色
- 如果點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)