zoukankan      html  css  js  c++  java
  • 判断单向连通图(拓扑排序+tarjan缩点)

    题意: 给你一个有向图,如果对于图中的任意一对点u和v都有一条从u到v的路或从v到u的路,那么就输出’Yes’,否则输出’No’.

    理解:当出现两个及以上入度为0的点(有一个就可能是别人到它,有两个的话那么那两个就互相到不了,因为他们入度都为0),就必定有不满足连通性的,但是如果只是单纯判断出度入度,会将重边误算,所以应该要用拓扑排序。拓扑排序之前,应该先进行缩点。

    注意:多组数据,要记得清0!!

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e3+5;
    const int M=N*N;
    int to[M],t[M],head[N],hea[N],nex[M],ne[M],tot,tott;
    int cnt,T,stk[N],flag[N],low[N],vis[N],top,bel[N];
    queue<int >q;
    int in[N];
    void add1(int a,int b)
    {
        to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
    }
    void add2(int a,int b)
    {
        t[++tott]=b; ne[tott]=hea[a]; hea[a]=tott;
    }
    void init()
    {
        top=0,tot=0,tott=0,cnt=0,T=0;
        memset(to,0,sizeof(to));memset(t,0,sizeof(t));
        memset(head,0,sizeof(head));memset(hea,0,sizeof(hea));
        memset(nex,0,sizeof(nex));memset(ne,0,sizeof(ne));
        memset(vis,0,sizeof(vis));memset(low,0,sizeof(low));
        memset(stk,0,sizeof(stk));memset(in,0,sizeof(in));
        memset(flag,0,sizeof(flag));
        while(!q.empty()) q.pop();
    } 
    void tarjan(int x)
    {
        vis[x]=low[x]=++T;
        stk[++top]=x; flag[x]=1;
        for(int i=head[x];i;i=nex[i])
        {
            int v=to[i];
            if(!vis[v])
            { tarjan(v); low[x]=min(low[x],low[v]); }
            else if(flag[v])
            low[x]=min(low[x],vis[v]);
        }
        if(vis[x]==low[x])
        {
            cnt++;
            do{
                flag[stk[top]]=0; bel[stk[top]]=cnt;
            }while(stk[top--]!=x);
        }
    }
    void build(int u)
    {
        for(int i=head[u];i;i=nex[i])
        if(bel[u]!=bel[to[i]])
        add2(bel[u],bel[to[i]]),in[bel[to[i]]]++;//bel[to[i]]!!
    }
    bool topo()
    {
        //printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++)
        if(!in[i]) q.push(i);
        while(!q.empty())
        {
            if(q.size()>1) return false;
            int u=q.front();
            q.pop();
            for(int i=hea[u];i;i=ne[i])
            {
                int v=t[i]; 
                in[v]--;
                if(!in[v]) q.push(v);
            }
        }
        return true;
    }
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        int n,m,Ti,a,b;
        scanf("%d",&Ti);
        while(Ti--)
        {
            init();
            scanf("%d%d",&n,&m);
            for(int i=1;i<=m;i++)
            scanf("%d%d",&a,&b),add1(a,b);
            for(int i=1;i<=n;i++)
            if(!vis[i])
            tarjan(i);
            for(int i=1;i<=n;i++)
            build(i);
            if(!topo()) printf("No
    ");
            else printf("Yes
    ");
        }
        
        
    }
    /*
    2
    3 2
    1 3
    2 3
    3 2
    1 2
    2 3
    */
  • 相关阅读:
    是否可能两个ETH私钥对应同一个地址
    使用 neon-wallet-db + neon-js + NEO-cli /rpc 搭建轻钱包服务端
    从源码看 angular/material2 中 dialog模块 的实现
    个人从源码理解JIT模式下angular编译AppModule的过程
    个人从源码理解angular项目在JIT模式下的启动过程
    使用angular的HttpClient搭配rxjs
    把angular项目整合到.net mvc中
    小程序开发整理
    ABC: Always Be Coding
    postgresql的psql常用命令-4
  • 原文地址:https://www.cnblogs.com/mowanying/p/10650423.html
Copyright © 2011-2022 走看看