【判定弱连通】==【tarjan求scc + 缩点+拓扑】

来源:互联网 发布:windows10改mac地址 编辑:程序博客网 时间:2024/05/23 01:59

给你一个N个点M条边的有向图,判断该图是否为弱连通。

思路:首先tarjan求SCC + 缩点,建成新图后,可以证明的是,新图必定有入度为0的点。在保证每个点都有边相连的前提下,我们进行一次拓扑排序,在这个过程中若遇到不符合弱连通的条件即跳出。反之一直处理到队列为空,这时说明该图为弱连通图。

遵循条件
一:新图不能有多于1个的入度为0的点,这是保证每个点都有边相连。
二:在拓扑排序遍历点u的过程中,若去掉与u相关的边后出现多于1个的入度为0的点,说明这些点只能由u到达,而它们之间不存在可达路径。这时不满足弱连通,跳出。
(其实就是 缩点后的新图,一定要有一个 确切的序列 —这样才说明图是一个弱连通)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<iostream>#include<vector>using namespace std;const int MAXN= 10010+10;struct Edge {    int from,to,next;}edge[60000+10];int head[MAXN],top;int n,m;void init(){    memset(head,-1,sizeof(head));    top=0;}void addedge(int a,int b){    Edge e={a,b,head[a]};    edge[top]=e;head[a]=top++;}void getmap(){    int a,b;  while(m--){    scanf("%d%d",&a,&b);    addedge(a,b);  }}int low[MAXN],dfn[MAXN];int scc_cnt,sccno[MAXN];stack<int>S;int Instack[MAXN];vector<int>G[MAXN];int dfs_clock;void tarjan(int now,int par){    low[now]=dfn[now]=++dfs_clock;    S.push(now);Instack[now]=1;    for(int i=head[now];i!=-1;i=edge[i].next){        Edge e=edge[i];        if(!dfn[e.to]){            tarjan(e.to,now);            low[now]=min(low[now],low[e.to]);        }else if(Instack[e.to])        low[now]=min(low[now],dfn[e.to]);    }    if(low[now]==dfn[now]) {        scc_cnt++;        for(;;){            int nexts=S.top();S.pop();Instack[nexts]=0;            sccno[nexts]=scc_cnt;            if(nexts==now) break;        }    }}void find_cut(int le,int ri){    memset(low,0,sizeof(low));    memset(dfn,0,sizeof(dfn));    memset(Instack,0,sizeof(Instack));    memset(sccno,0,sizeof(sccno));    dfs_clock=scc_cnt=0;    for(int i=le;i<=ri;i++){        if(!dfn[i]) tarjan(i,-1);    }}int in[MAXN];void suodian(){    for(int i=1;i<=scc_cnt;i++) {            in[i]=0;G[i].clear();    }    for(int i=0;i<top;i++){        Edge e=edge[i];        int now=sccno[e.from];        int nexts=sccno[e.to];        if(now!=nexts){            G[now].push_back(nexts);            in[nexts]++;        }    }}queue<int>Q;bool topo(){    while(!Q.empty()) Q.pop();    int num=0;    for(int i=1;i<=scc_cnt;i++){        if(!in[i]) {            Q.push(i);            num++;            if(num>1) return false;        }    }    int k=0;    while(!Q.empty()){        int now=Q.front();Q.pop();num=0;k++;        for(int i=0;i<G[now].size();i++){            int v=G[now][i];            if(--in[v]==0){                Q.push(v);                num++;                if(num>1) return false;            }        }    }    return  k==scc_cnt; // 可能缩点后的新图本身就不是连通的}void solve(){    find_cut(1,n);    suodian();    if(scc_cnt==1) puts("Yes");    else    puts(topo()?"Yes":"No");}int main(){    int t;cin>>t;while(t--){        cin>>n>>m;        init();        getmap();        solve();    }    return 0;}
阅读全文
0 0
原创粉丝点击