• BDFZOI 边的分类


    涉及知识:基础图论/DFS

    提交次数:4

    描述

    给定无权有向图G(V,E),dfs确定每条边的种类。当边(u, v)第一次被遍历,

    考虑v的颜色

    1.白色,(u,v)为T边,包含在dfs树中

    2.灰色,(u,v)为B边,dfs树中子孙指向自己直系祖先的一条边

    3.黑色: (u,v)为F边或C边. 此时需要进一步判断

    3.1. 若prev[u]<prev[v]:u是v的直系祖先,F边<prev[v]:u是v的直系祖先,f边

    3.2. 若prev[u]>prev[v]:v早就被发现了, C边

    输入

    第一行包含两个整数N、M,表示该图共有N个结点和M条有向边。(N <= 5000,M <= 200000)
    接下来M行,每行包含2个整数{u,v},表示有一条有向边 u指向v

    输出

    M行,依照输入顺序,每行输出边的u、v、种类

    样例输入

    5 9
    1 2
    1 3
    1 4
    2 3
    3 4
    3 5
    5 1
    5 2
    5 4

    样例输出

    1 2 T
    1 3 F
    1 4 F
    2 3 T
    3 4 T
    3 5 T
    5 1 B
    5 2 B
    5 4 C

    代码:
     1 #include<iostream>
     2 #include<vector>
     3 #include<cstring>
     4 #include<cstdio>
     5 using namespace std;
     6 int n, m;
     7 struct edge{
     8     int u, e;
     9 };
    10 vector<vector<edge> >v(5005);
    11 int dfn[5005];
    12 int finish[5005];
    13 bool visited[5005];
    14 int ttime;
    15 
    16 void dfs(int uu, int step){
    17     dfn[uu] = ttime++;
    18     for(int i = 0; i < v[uu].size(); i++){
    19         int next = v[uu][i].u;
    20         if(dfn[next]==-1) v[uu][i].e = 1;//T边 
    21         else if (finish[next]==-1) v[uu][i].e = 2;//B边
    22         else{
    23             if(dfn[next]>dfn[uu]) v[uu][i].e = 3; //F边
    24             else if (dfn[next]<dfn[uu]) v[uu][i].e = 4;//C边 
    25         }
    26         if(visited[next]==false){
    27             visited[next] = true;
    28             dfs(next, step+1);
    29         }
    30     }
    31     finish[uu] = ttime++;
    32 }
    33 int main(){
    34     cin>>n>>m;
    35     int i, j;
    36     for(i = 1; i <= m; i++){
    37         edge ee;
    38         int a, b;
    39         cin>>a>>b;
    40         ee.u = b;
    41         ee.e = 0;
    42         v[a].push_back(ee); 
    43     }
    44     memset(dfn,-1,sizeof(dfn));
    45     memset(finish,-1,sizeof(finish));
    46     visited[1] = true;    
    47     dfs(1,0);
    48     for(i = 1; i <= n; i++){
    49         if(!visited[i]){
    50             visited[i] = true;
    51             dfs(i,0);
    52         }
    53     }
    54     for(i = 1; i <= n; i++)
    55         for(j = 0; j < v[i].size();j++){
    56             switch(v[i][j].e){
    57                 case 1:
    58                     cout<<i<<" "<<v[i][j].u<<" "<<"T"<<endl;
    59                     break;
    60                 case 2:
    61                     cout<<i<<" "<<v[i][j].u<<" "<<"B"<<endl;
    62                     break;
    63                 case 3:
    64                     cout<<i<<" "<<v[i][j].u<<" "<<"F"<<endl;
    65                     break;
    66                 case 4:
    67                     cout<<i<<" "<<v[i][j].u<<" "<<"C"<<endl;
    68                     break;
    69             }        
    70         }
    71         
    72     return 0;
    73 } 
    备注:
    这周上课时老师补充的内容,属于比较基础的内容。利用dfs树,设置两个时间戳dfn[i]为发现结点i的时间,finish[i]为离开这个点,
    也就是出栈的时间戳。这样就可以将点染色,白色为未访问的结点,即dfn为-1;灰色为已发现,但未完成的结点;黑色则为已完成的结点,
    即finish!=-1。于是也可以把边进行分类了,分为树边,前向边,后向边和叉边。具体见dfs内的几行代码。
    T树边:灰->白
    B后向边:灰->灰
    F前向边:灰->黑
    C叉边:灰->黑
    无向图没有后两者。
    还是犯了一些错误的。比如每个点都只能访问一次,对于已经访问过的点,只要判断一下边,不能接着dfs下去。
    还有就是图不一定连通,所以每个点都要判断一下要不要dfs。另外得4分是因为忘了标记再次dfs的点。

  • 相关阅读:
    SendMessage 关闭外部程序
    ShellApi 列举正在运行的程序
    SendMessage 关闭显示器
    ShellAPI 自定义系统的关于对话框 about
    if 条件语句
    操作INI文件cpp
    ShellAPI 取得可执行文件的图标
    For 循环 语句
    选择结构语句IF
    SendMessage 关闭计算器
  • 原文地址:https://www.cnblogs.com/fangziyuan/p/7030301.html
Copyright © 2020-2023  润新知