zoukankan      html  css  js  c++  java
  • poj2186--tarjan+缩点(有向图的强连通分量中点的个数)

    题目大意:

          每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
    种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
    牛被所有的牛认为是受欢迎的。
     
          先用tarjan求出每个强连通分量,再缩点,统计每个点的出度,如果有且只有1个出度为0的点,就输出这个点包含的节点数,否则输出0.
     
    证明:
          如果有强连通分量被孤立(即和其他强连通分量无边相连),那么答案一定是0,此时由于缩点后是一个DAG图,出度为0的点的个数一定大于1.
          如果没有点被孤立,当出度为0的点多于1个时,由DAG图的性质可得,一定不存在一个点能从其他所有点到达。只有当出度为0的点的个数等于1时,这个出度为0的点才能被其他所有点到达。
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define cls(s,h) memset(s,h,sizeof s)
    const int maxn = 1e5 + 7;
    int n , m ;
    int tot;
    struct  edge
    {
        int to,from,nxt;
    }e[maxn << 1];
    
    int head[maxn];
    void add_edge(int u , int v ){
        e[tot].from = u ;
        e[tot].to = v;
        e[tot].nxt = head[u];
        head[u] = tot++;
    }
    
    int stack[maxn << 1],low[maxn << 1],dfn[maxn << 1];
    int scc,sz[maxn << 1],c[maxn << 1],st,num;
    void init(){
        cls(head,-1);
        cls(e,0);
        cls(sz,0);
        scc = 0;
        st = 0;
    }
    
    
    void tanjan(int u){
        stack[++st] = u;
        dfn[u] = low[u] = ++ num;
        for(int i = head[u],v; ~i ;i = e[i].nxt){
            if(c[v = e[i].to]) continue;
            if(dfn[v]) low[u] = min(low[u],dfn[v]);
            else tanjan(v),low[u] = min(low[u],low[v]);
        }
        if(low[u] == dfn[u]){
            c[u] = ++ scc; sz[scc] = 1;
            while(st && u != stack[st])
                //SCC number and the scc ge SCC
                c[stack[st--]] = scc,sz[scc] ++;
            st--;
        }
    }
    
    int out[maxn << 1];
    int main(int argc, char const *argv[])
    {
        init();
        scanf("%d %d",&n,&m);
        for(int i = 1,u,v;i <= m ;i ++)
        scanf("%d %d",&u,&v),add_edge(u,v);
        
        for(int i = 1;i <= n;i ++)
            if(!dfn[i]) tanjan(i);
        for(int i = 0;i < tot;i ++)
            if(c[e[i].from] != c[e[i].to]) out[c[e[i].from]] ++;
        int ans = 0;
        for(int i = 1;i <= scc;i ++)
            if(!out[i]) ans = ans ? -1: i;
        if(~ans) ans = sz[ans];
        else ans = 0;
        printf("%d
    ", ans);
        return 0;
    }
    View Code
    //如果没有点被孤立,当出度为0的点多于1个时,
    //由DAG图的性质可得,一定不存在一个点能从其他所有点到达。
    //只有当出度为0的点的个数等于1时,
    //这个出度为0的点才能被其他所有点到达。
    //因为如果存在两个,那么就会少一个点
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define cls(s,h) memset(s,h,sizeof s)
    const int maxn = 1e5 + 7;
    int n , m ;
    int tot;
    struct  edge
    {
        int to,from,nxt;
    }e[maxn << 1];
    
    int head[maxn];
    void add_edge(int u , int v ){
        e[tot].from = u ;
        e[tot].to = v;
        e[tot].nxt = head[u];
        head[u] = tot++;
    }
    
    int stack[maxn << 1],low[maxn << 1],dfn[maxn << 1];
    int scc,sz[maxn << 1],c[maxn << 1],st,num;
    void init(){
        cls(head,-1);
        cls(e,0);
        cls(sz,0);
        scc = 0;
        st = 0;
    }
    
    
    void tanjan(int u){
        stack[++st] = u;
        dfn[u] = low[u] = ++ num;
        for(int i = head[u],v; ~i ;i = e[i].nxt){
            if(c[v = e[i].to]) continue;
            if(dfn[v]) low[u] = min(low[u],dfn[v]);
            else tanjan(v),low[u] = min(low[u],low[v]);
        }
        if(low[u] == dfn[u]){
            c[u] = ++ scc; sz[scc] = 1;
            while(st && u != stack[st])
                //强连通分量的编号和其中点的个数
                //SCC number and the scc ge SCC
                c[stack[st--]] = scc,sz[scc] ++;
            st--;
        }
    }
    
    int out[maxn << 1];
    int main(int argc, char const *argv[])
    {
        init();
        scanf("%d %d",&n,&m);
        for(int i = 1,u,v;i <= m ;i ++)
        scanf("%d %d",&u,&v),add_edge(u,v);
        
        for(int i = 1;i <= n;i ++)
            if(!dfn[i]) tanjan(i);
        for(int i = 0;i < tot;i ++)
            if(c[e[i].from] != c[e[i].to]) out[c[e[i].from]] ++;
        int ans = 0;
        for(int i = 1;i <= scc;i ++)
            if(!out[i]) ans = ans ? -1: i;
        if(~ans) ans = sz[ans];
        else ans = 0;
        printf("%d
    ", ans);
        return 0;
    }
    更新代码
  • 相关阅读:
    查看数据库表中的数据
    exec和execsql
    CPI
    百度硬盘可以检索的字节测试
    HDU2095
    Vigenere密码
    斌神无所不能
    HDU p1017
    POJ1316
    head区的代码详解
  • 原文地址:https://www.cnblogs.com/DWVictor/p/11332838.html
Copyright © 2011-2022 走看看