码迷,mamicode.com
首页 > 其他好文 > 详细

DFS树的性质

时间:2020-08-28 14:36:25      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:nim   情况   int   net   如何   tail   参考   head   process   

参考了这篇文章.

无向图的DFS树

技术图片
技术图片

在DFS树上的边称为树边。
对于非树边 \((u,v)\),如果 \(v\)\(u\) 在DFS树上的祖先,称它为后向边;如果 \(v\)\(u\) 在DFS树上的后裔,称它为前向边。
易证,无向图没有横叉边。
非树边一定不是桥。边 \((u,v)\) 是桥,当且仅当 \((u,v)\) 是树边,并且没有非树边跨越这条边。

如何求桥?

1.Tarjan 算法

待续。

2.树上dp

\(fa\)\(u\) 的父亲,\(dp[u]\) 表示跨越 \(u\) 和它父亲的非树边的数量,则

\[dp[u]=\sum_{(u,v)是后向边} 1+\sum_{v是u的儿子,(u,v)是树边} dp[v]-\sum_{(u,v)是前向边} 1 \]

如果 \(dp[u]=0\),则 \(u\) 和连接DFS树上的它父亲的这条边是桥。

Code
代码是[HDU 4738]这题的一部分,是要求所有桥的边权的最小值,由于无向图没有横叉边,我们可以用DFS的时间戳 \(DFN\) 来判断祖先和后裔的关系。

struct Graph{
    struct edge{int Next,to,w;};
    edge G[2000010];
    int head[1010];
    int cnt;

    Graph():cnt(2){}
    void clear(int node_num=0){
        cnt=2;
        if(node_num==0) memset(head,0,sizeof(head));
        else fill(head,head+node_num+5,0);
    }
    void add_edge(int u,int v,int w){
        G[cnt].w=w;
        G[cnt].to=v;
        G[cnt].Next=head[u];
        head[u]=cnt++;
    }
};
Graph G;
int dp[1010],DFN[1010];
bool vis[1010];
int N,M,Index,Ans;

void DFS(int u,int fa,int w,int id){
    vis[u]=true;
    DFN[u]=++Index;
    dp[u]=0;
    for(int i=G.head[u];i;i=G.G[i].Next){
        int v=G.G[i].to;
        if(!vis[v]){DFS(v,u,G.G[i].w,i);dp[u]+=dp[v];}//树边
        else if(v!=fa || (v==fa && i!=id && (i^1)!=id)){//非树边,考虑了重边的情况
            if(DFN[v]<DFN[u]) ++dp[u];//后向边
            else --dp[u];//前向边
        }
    }
    if(dp[u]==0 && fa) Ans=min(Ans,w);//没有非树边跨越u和他父亲,那么这条边是桥
    return;
}

DFS树的性质

标签:nim   情况   int   net   如何   tail   参考   head   process   

原文地址:https://www.cnblogs.com/AEMShana/p/13551361.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!