DAG 的深度优先搜索标记 (参考的一个acm模板,不知道挂啥链接)
邻接矩阵版
/*==================================================*\
| DAG 的深度优先搜索标记
| INIT: edge[][]邻接矩阵; pre[], post[], tag全置0;
| CALL: dfstag(i, n); pre/post:开始/结束时间
\*==================================================*/
/*
注意:发起点——>接受点,中间->即为边,种类如下:
树边(Tree Edge):从一个顶点指向其未访问过的子节点的边。
前向边(Forward Edge):从一个顶点指向该顶点的一个非子顶点后裔的边,且 接受点 被访问过。
回边(Back Edge):从一个顶点指向其祖先顶点的边。
横跨边(Cross Edge):从一个顶点指向一个已完全访问过的顶点,且其中 接受点 既不是 发起点 的的后裔,也不是其祖先。
*/
int edge[V][V], pre[V], post[V], tag; //置零
void dfstag(int cur, int n){
// vertex: 0 ~ n-1
pre[cur] = ++tag; // 开始访问cur
for(int i = 0; i < n; ++i) //依次访问cur的 ‘子孙’ 结点
if(edge[cur][i]){
if(pre[i] == 0){ // i 未被访问
cout << "edge" << cur << -> << i << "is Tree Edge" << endl;
dfstag(i, n);
}
else{
if(post[i] == 0) // i 子孙后代未被访问完
cout << "edge" << cur << -> << i << "is Back Edge" << endl;
else if (pre[i] > pre[cur]) //i 在 cur之后访问
cout << "edge" << cur << -> << i << "is Down Edge" << endl;
else cout << "edge" << cur << -> << i << "is Cross Edge" << endl; //指向一个完全访问了的结点
}
}
post[cur] = ++tag; // cur访问结束
}
/*
DFS过程中,对于一条边cur->i:
pre[i] = 0:说明i还没被访问,i是首次被发现,cur->i是一条 树边 ,真正的dfs路径中的边。
pre[i]!= 0:
pos[i] = 0:说明i已经被访问,但其子孙后代还没有被访问完, 此时正在结束cur的所有孩子的访问,处于i的递归层次中,而cur又指向i,说明cur就是i的子孙后代,cur->i是一条 后向边 ,因此后向边又称返祖边,有环的时候回去的边,因此判断有没有环可以判断有没有后向边就可以了。
pos[i] != 0:
pre[i] > pre[cur]:说明i已经被访问,其子孙后代也已经全部访问完,cur->i是一条 前向边 ,前向边可以理解为就是父亲指向孩子,但是已经访问过了(非直接孩子)。
树边,后向边,前向边,都有祖先,后裔的关系,但横跨边没有,cur->i为横跨边,说明在这棵DFS树中,它们不是祖先后裔的关系它们可能是兄弟关系,堂兄弟关系,甚至更远的关系,如果是dfs森林的话,cur和i甚至可以在不同的树上。
*/
邻接表版
int pre[V], post[V], tag; //置零
vector<vector<int> > adj;
void dfstag(int cur, int n){
// vertex: 0 ~ n-1
pre[cur] = ++tag; // 开始访问cur
for(int i = 0; i < adj[cur].size(); ++i){ //依次访问cur的 ‘子孙’ 结点
int child = adj[cur][i];
if(pre[child] == 0){ // child 未被访问
cout << "edge" << cur << -> << child << "is Tree Edge" << endl;
dfstag(child, n);
}
else{
if(post[child] == 0) // child 子孙后代未被访问完
cout << "edge" << cur << -> << child << "is Back Edge" << endl;
else if (pre[child] > pre[cur]) //child 在 cur之后访问
cout << "edge" << cur << -> << child << "is Down Edge" << endl;
else cout << "edge" << cur << -> << child << "is Cross Edge" << endl; //指向一个完全访问了的结点
}
}
post[cur] = ++tag; // cur访问结束
}