DAG的深度优先搜索标记学习日志

首先,针对一个这样的题目开始我们的学习:                             
 
 

输入一个有向图,从顶点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;
        }
    }
}                                 


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值