POJ - 2762 Going from u to v or from v to u? (强连通缩点+判断单向连通)

题意:判断一个有向图中的任意两点u、v,是否可以由其中一个点到达另一个点。

分析:这个问题转化以后就是:将该图强连通缩点后再判断其是否是单向连通的。缩点用Tarjan处理强连通分量。

有一个定理是这样的:一个有向图是单项连通的当且仅当其拓扑排序唯一。那么将这个子问题再转化为其缩点之后的图拓扑排序是否唯一。

如果一个有向图拓扑排序唯一,那么在根据入度求拓扑排序的过程中,不会有超过一个点在同一时刻同时为0。

#include<stack>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long LL;
const int MAXN = 1e3+10;
struct Edge{
    int to,next;
}edges[MAXN<<3],E[MAXN<<3];
int ID,H[MAXN];
int dfn[MAXN],low[MAXN],sccno[MAXN],head[MAXN],tot,dfs_clock,scc_cnt,in[MAXN],sccnum[MAXN];
stack<int> S;

void init()
{
    ID=dfs_clock=tot=scc_cnt=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(in,0,sizeof(in));
    memset(sccno,0,sizeof(sccno));
    memset(head,-1,sizeof(head));
    memset(H,-1,sizeof(H));
}

void Tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++dfs_clock;
    S.push(u);
    for(int i=head[u];~i;i=edges[i].next){
        v = edges[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u]){
        ++scc_cnt;
        while(true){
            int x = S.top();S.pop();
            sccno[x] = scc_cnt;
            if(x==u) break;
        }
    }
}

void AddEdge(int u,int v)
{
    edges[tot]=(Edge){v,head[u]};
    head[u]=tot++;
}
void new_AddEdge(int u,int v){
    E[ID]= (Edge){v,H[u]};
    H[u]=ID++;
}

bool Topo()
{
    queue<int> Q;
    for(int u=1;u<=scc_cnt;++u){
        if(!in[u]) Q.push(u);
    }
    if(Q.size()>1) return false;
    while(!Q.empty()){
        int x = Q.front();Q.pop();
        for(int i=H[x];~i;i=E[i].next){
            int v =E[i].to;
            in[v]--;
            if(!in[v]) Q.push(v);
        }
        if(Q.size()>1) return false;
    }
    return true; 
}

int main()
{
    #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
    #endif
    int T,N,M,u,v;
    scanf("%d",&T); 
    while(T--){
        scanf("%d%d",&N,&M);
        init();
        for(int i=1;i<=M;++i){
            scanf("%d%d",&u,&v);
            AddEdge(u,v);
        }
        for(int i=1;i<=N;++i){
            if(!dfn[i])Tarjan(i);
        }
        for(int u=1;u<=N;++u){
            for(int i=head[u];~i;i=edges[i].next){
                int v=edges[i].to;
                if(sccno[u]!=sccno[v]){
                    new_AddEdge(sccno[u],sccno[v]);
                    in[sccno[v]]++;
                }
            }            
        }
        if(Topo()||scc_cnt==1) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

 

posted @ 2018-07-31 13:08  xiuwenL  阅读(152)  评论(0编辑  收藏  举报