POJ2762判断图是否单向连通,缩点+dfs

来源:互联网 发布:java语言的编译原理 编辑:程序博客网 时间:2024/05/22 09:38
/*题意:判断所给图是否为单向连通图先Tarjan缩点;对于缩点之后的图的每一条边正反两个方向DFS,分别统计由这条边出去(out)和进来(in)能到达的点数,将统计的结果加到边所连接的两点上去,边的起点+out的结果,边的终点加上in的结果,最后判断每个点的结果是否为总点数-1。写完后google一下,证明我的原创算法又不是主流的算法,。。。其实当且仅当缩点后的图为一条单链时,图为单向连通图,这样dfs就好写多了,看poj status 别个的时间也不比俺优,哈哈*/#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;const int NN=1005;const int MM=10000;vector<int> adj[NN];int n,m;struct Edge{               //缩点后的边,next双域存正反两个方向    int u,v,next1,next2;}e[MM];int ecnt,head1[NN],head2[NN];void addedge(int u,int v){    ecnt++;    e[ecnt].u=u;    e[ecnt].v=v;    e[ecnt].next1=head1[u];    e[ecnt].next2=head2[v];    head1[u]=head2[v]=ecnt;}int depth,top,bcnt;int dfn[NN],low[NN],belong[NN],stack[NN];bool instack[NN];void tarjan(int u){    dfn[u]=low[u]=++depth;    stack[++top]=u;    instack[u]=true;    int v;    for (int i=0; i<adj[u].size(); i++)    {        v=adj[u][i];        if (!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if (instack[v])            low[u]=min(low[u],dfn[v]);    }    if (low[u]==dfn[u])    {        bcnt++;        do{            v=stack[top--];            instack[v]=false;            belong[v]=bcnt;        }while (v!=u);    }}int in[NN],out[NN];void out_dfs(int i){    if (out[i]) return;    int u=e[i].v;    for (int j=head1[u]; j!=-1; j=e[j].next1)    {        out_dfs(j);        out[i]+=out[j];    }    out[i]+=1;}void in_dfs(int i){    if (in[i]) return;    int u=e[i].u;    for (int j=head2[u]; j!=-1; j=e[j].next2)    {        in_dfs(j);        in[i]+=in[j];    }    in[i]+=1;}int r[NN];bool ok(){    bcnt=top=depth=0;    for (int i=1; i<=n; i++)    {        instack[i]=false;        dfn[i]=0;    }    for (int i=1; i<=n; i++)      if (!dfn[i]) tarjan(i);    if (bcnt==1) return true;  //图是强连通的可提前退出    ecnt=0;    for (int i=1; i<=bcnt; i++) head1[i]=head2[i]=-1;    for (int u=1; u<=n; u++)    {        for (int i=0; i<adj[u].size(); i++)        {            int v=adj[u][i];            if (belong[u]!=belong[v]) addedge(belong[u],belong[v]);        }    }    for (int i=1; i<=ecnt; i++) out[i]=in[i]=0;    for (int i=1; i<=ecnt; i++) out_dfs(i),in_dfs(i);    for (int i=1; i<=bcnt; i++) r[i]=0;    for (int i=1; i<=ecnt; i++)    {        r[e[i].u]+=out[i];        r[e[i].v]+=in[i];    }    for (int i=1; i<=bcnt; i++) if (r[i]!=bcnt-1) return false;    return true;}int main(){    int cas,x,y;    scanf("%d",&cas);    while (cas--)    {        scanf("%d%d",&n,&m);        for (int i=1; i<=n; i++) adj[i].clear();        for (int i=1; i<=m; i++)        {            scanf("%d%d",&x,&y);            adj[x].push_back(y);        }        if (ok()) printf("Yes\n");        else      printf("No\n");    }    return 0;}