牛客小白月赛12 I 华华和月月逛公园 Tarjan算法求隔边

题目链接:https://ac.nowcoder.com/acm/contest/392/I

题意:给你一个连通的无向图,问图的隔边有多少条

输入:N,M分别是点数和边数

之后M行每行两个正整数u,v表示无向边

强连通分量:如果一个有向图任意两点都是互相可达的,这个图就是强连通分量

不过我们这个题是无向图,所以要改一点

这个博客讲的还蛮好的:https://blog.csdn.net/mengxiang000000/article/details/51672725

不过他说的有一点有问题,如果在遍历一个点的边时,边已经被访问过了,那作比较的就不是两个点的low值了,而是自己的low值和下一个点的dfn值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=1<<30;
const int maxn=1e5+7;
const double pi=acos(-1);
const int mod=1000000007;
int n,m,cnt,ans,dfn[maxn],low[maxn];
vector<int> v[maxn];
inline void read(int &x){
    char ch=x=0;
    while(!isdigit(ch))
        ch=getchar();
    while(isdigit(ch))
        x=x*10+ch-'0',ch=getchar();
}
void Tarjan(int now,int fa){
    dfn[now]=low[now]=++cnt;
    for(int i=0;i<v[now].size();i++){
        if(!dfn[v[now][i]]){//如果这个点还没有被走过,就走这个点,如果走过dfn肯定被定义过,直接用dfn判断,省一个vis数组 
            Tarjan(v[now][i],now);//对这个点再用Tarjan算法,并记得把父亲给传过去
            low[now]=min(low[now],low[v[now][i]]);//等走完之后再来更新本节点的low值,没走过就是两个low比 
            if(low[v[now][i]]>dfn[now]) ans++;//回溯之后如果now和其子节点在同一个强连通分量里,子节点的low值应该更新为
            //now的dfn值(因为是从now节点更新的,一个强连通分量里仅有一个特殊的点,就是起始点,其他店的low值都会更新为
            //它的,所以若不同则说明不再一个强连通分量里 )
        }
        else if(v[now][i]!=fa) low[now]=min(low[now],dfn[v[now][i]]);
        //如果已经走过且不是父亲的话(因为是无向边所以还要标记父亲),那就更新节点的low值吧 
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int x,y;
    int t=m;
    while(t--){
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    Tarjan(1,0);//因为题目说过保证联通,所以不需要再用for循环 
    //cout<<ans<<" "<<m<<endl;
    cout<<m-ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/10554812.html