生活随笔
收集整理的這篇文章主要介紹了
DAG的深度优先搜索标记
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這是圖論的基礎知識點,也是學習Tarjan的導學課。
一、知識
對于在圖G上進行深度優先搜索算法所產生的深度優先森林Gt,我們可以定義四種邊的類型:
1.樹邊(Tree Edge):為深度優先森林中Gt的邊。如果結點v是因算法對邊(u,v)的搜索而首先被發現,則(u,v)是一條樹邊。
2.后向邊(Back Edge):后向邊(u,v)是將結點u連接到其在深度優先樹中(一個)祖先結點v的邊,由于有向圖中可以有自循環,自循環也被認為是后向邊。
3.前向邊(Forward Edge):是將結點u連接到其在深度優先樹中一個后代結點v的邊(u,v)。
4.橫向邊(Cross Edge):指其他所有的邊。這些邊可以連接同一棵深度優先樹中的結點,只要其中一個結點不是另外一個結點的祖先,也可以連接不同深度優先樹中的兩個結點。
附圖:
二、方法
我們采取時間戳的思想:不會戳這里。
1.我們根據深度優先搜索的基本操作需要一個記錄頂點相連的標志,也就是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了。
#include<iostream>
#include<queue>
#include<algorithm>
#include<set>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<bitset>
#include<cstdio>
#include<cstring>
#define cini(n) scanf("%d",&n)
#define cinl(n) scanf("%lld",&n)
#define cinc(n) scanf("%c",&n)
#define cins(s) scanf("%s",s)
#define coui(n) printf("%d",n)
#define couc(n) printf("%c",n)
#define coul(n) printf("%lld",n)
#define debug(n) printf("%d_________________________________\n",n);
#define speed ios_base::sync_with_stdio(0)
#define file freopen("input.txt","r",stdin);freopen("output.txt","w",stdout)
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Swap(a,b) a^=b^=a^=b
#define Max(a,b) (a>b?a:b)
#define Min(a,b) a<b?a:b
#define mem(n,x) memset(n,x,sizeof(n))
#define mp(a,b) make_pair(a,b)
#define pb(n) push_back(n)
#define dis(a,b,c,d) ((double)sqrt((a-c)*(a-c)+(b-d)*(b-d)))
#define INF 0x3f3f3f3f
#define esp 1e-9
#define PI acos(-1)
using namespace std
;
#define maxn 1020
#define INF 0x3f3f3f3fusing 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;}}
}
總結
以上是生活随笔為你收集整理的DAG的深度优先搜索标记的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。