DAG的深度優先搜尋標記學習日誌
阿新 • • 發佈:2019-01-03
首先,針對一個這樣的題目開始我們的學習:
輸入一個有向圖,從頂點1開始做dfs對邊進行分類。
Input輸入的第一行包含兩個整數n和m,n是圖的頂點數,m是邊數。1<=n<=100,0<=m<=10000。
接下來的m行,每行是一個數對u v,表示存在有向邊(u,v)。頂點編號從1開始。接下來的1行,包含一個整數k,表示會查詢k條邊的型別。
接下來的k行,每行是一個數對u v,表示查詢邊u v的型別。
那麼:我們先來熟悉一下怎麼樣算是邊的分類,也就是有哪些邊的種類1、樹邊 Tree edge
2、向前邊 Forward edge(本題目中為Down edge)
3、向後邊 Back edge
4、橫叉邊 Cross edge
那麼我們怎麼利用這樣的分類區分不同的邊呢? 首先,我們根據深度優先搜尋的基本操作需要一個記錄頂點相連的標誌,也就是edge[][]的一個二維陣列, 然後,在遍歷各個頂點的過程中將遇到的可以訪問的edge設定為-1(初始化為0,輸入時置為1)也就是已經訪問過了, 至此,我們的樹就會生成,但是我們需要記錄其中不同邊的特性,所以,我們增加兩個標誌位pre,post來記錄開始和結束的時間點, 這個時間點起始點為0. 每當進行一次遍歷則會將對應的時間點記錄到相應頂點的pre和post中去,因此,我們可以有這樣的想法: 1、需要判斷一條邊為back edge的話,只需要檢視其相連頂點的post是否存在就可以了,因為從上到下的搜尋過程中,只有該頂點結束搜尋才會設定相應的結束時間 因而如果當前頂點的遍歷都沒有結束那麼說明與該點相連的頂點形成的邊是一條bakc edge。 2、從剛剛到back edge判斷中我們可以聯想發現,如果當前的頂點需要遍歷且相連頂點的pre(開始時間)比當前頂點的pre高,說明這條邊跳過一些時間點直接到此點 而且還是從較早到時間點跳轉到較晚的時間點,因此這樣的一條邊是一條down edge。 3、可想而知如果一個頂點遍歷的開始時間點遠遠大於另外一個頂點點話,這樣形成的一條邊自然就是cross edge了。 至此,應該就能夠基本解決這道問題了:// Problem#: 12120 // Submission#: 3332350 // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License // URI: http://creativecommons.org/licenses/by-nc-sa/3.0/ // All Copyright reserved by Informatic Lab of Sun Yat-sen University #include "iostream" #include "cstring" #include "algorithm" #include "stdio.h" using namespace std; int pre[101],post[101],edge[101][101],parent[101]; int tag; void dfs_tag(int cur,int n){ pre[cur]=++tag; for(int i=0;i<n;i++){ if(edge[cur][i]==1){ if(pre[i]==0){ parent[i]=cur; edge[cur][i]=-1; dfs_tag(i,n); }else{ if(post[i]==0){edge[cur][i]=-2;} else if(pre[i]>pre[cur]){ edge[cur][i]=-3; }else{ edge[cur][i]=-4; } } } } post[cur]=++tag; } void dfs(int n){ memset(pre,0,sizeof(pre)); memset(post,0,sizeof(post)); memset(parent,-1,sizeof(parent)); for (int i = 0; i < n; ++i) { if(parent[i]==-1) dfs_tag(i,n); } } int main(){ int n,m; int u,v; int cases; tag=0; cin>>m>>n; for (int i = 0; i < m; ++i) { cin>>u>>v; edge[u][v]=1; } dfs(n); cin>>cases; while(cases--){ cin>>u>>v; switch(edge[u][v]){ case -1: printf("edge (%d,%d) is Tree Edge\n",u,v); break; case -2: printf("edge (%d,%d) is Back Edge\n",u,v); break; case -3: printf("edge (%d,%d) is Down Edge\n",u,v); break; case -4: printf("edge (%d,%d) is Cross Edge\n",u,v); break; } } }