zoukankan      html  css  js  c++  java
  • poj 1236 Network of Schools

    强连通分量 缩点

    题意:这个题意比较难懂,题意读懂了,转化过来也不容易

    输入n,表示n个学校(1到n编号),下面n行,分别是对应每个学校的信息。每个学校可以给其他学校共享一些软件接而共享下去,要让所有学校用上软件,需要多少个学校带头共享软件;另外要让每个学校共享的软件都能被其他所有学校用上,那么要在原来的共享计划中,另外加入那些具体的共享呢(例如原来A学校不向B学校共享的,为了达到目的,A学校需要向B学校共享,因而增加了1)

    首先建立有向图,A向B共享软件,则有向边A--->B

    所有第1个问题,问的就是要多少次才能遍历完整个有向图,因为有这么多的学校带头共享软件了,沿着路径延伸,可以到达他们子树下的所有点,要让所有学校用上软件(不一定用上相同的软件,即软件的来源可以不同),其实就是要到达图中的每个点

    做法是,将原图进行缩点,变成一个DAG,在这个DAG中,入度为0的点,就是答案(这个结论不难理解,思考一下即可)

    对于第2个问题,一个学校共享软件出来,要让所有其他学校用上,而且所有学校都要做到这点,那么狠显然,就是令整个图变成一个  强连通图  , 那么问题就是,要在原图中,添加多少条边,原图才能变成一个强连通图?

    答案是,将原图缩点,变成一个DAG,统计这个DAG入度为0的点的个数和出度为0的点的个数,答案就是两者中的较大值,因为有一个结论,这些边一定是出度为0点指向入度为0的点

    (这个结论也不太难理解,但是建议深入思考,最好证明)

    那么要实现这个代码,其实是不难的,建图,运行tarjan求强连通分量并且缩点,然后统计缩点后的DAG

    //将原图缩点为一个DAG
    //需要多少次才能遍历完这个DAG,就是看这个DAG有多少个入度为0的点
    //往这个DAG添加多少边才能使其成为强连通图,就是找出入度和出度为0的最大值
    
    #include <cstdio>
    #include <cstring>
    #define N 110
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    int n,tot;
    int dcnt,bcnt;
    int dfn[N] , low[N] , belong[N];
    int stack[N] , top;
    bool ins[N];
    int inde[N],outde[N];
    int head[N];
    struct edge
    {
        int u,v,next;
    }e[N*N];
    
    void add(int u ,int v)
    {
        e[tot].u = u; e[tot].v = v;
        e[tot].next = head[u]; head[u] = tot++;
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++dcnt;
        stack[++top] = u;
        ins[u] = true;
        for(int k=head[u]; k!=-1; k=e[k].next)
        {
            int v = e[k].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u] , low[v]);
            }
            else if(ins[v])
                low[u] = min(low[u] , dfn[v]);
        }
        if(dfn[u] == low[u])
        {
            ++bcnt;
            while(1)
            {
                int x = stack[top--];
                ins[x] = false;
                belong[x] = bcnt;
                if(x == u) break;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        tot = 0;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=n; i++)
        {
            int v;
            while(scanf("%d",&v)!=EOF && v)
                add(i,v);
        }
        dcnt = bcnt = top = 0;
        memset(dfn,0,sizeof(dfn));
        memset(belong,0,sizeof(belong));
        memset(ins,false,sizeof(ins));
        for(int i=1; i<=n; i++)
            if(!dfn[i])
                tarjan(i);
        if(bcnt == 1)
        {
            printf("1\n0\n");
            return 0;
        }
        memset(inde,0,sizeof(inde));
        memset(outde,0,sizeof(outde));
        for(int i=1; i<=n; i++)
            for(int k=head[i]; k!=-1; k=e[k].next)
            {
                int u = belong[i];
                int v = belong[e[k].v];
                if(u != v)
                {
                    outde[u]++;
                    inde[v]++;
                }
            }
        int res = 0 , _res = 0;
        for(int i=1; i<=bcnt; i++)
        {
            if(!inde[i]) res++;
            if(!outde[i]) _res++;
        }
        printf("%d\n%d\n",res,max(res , _res));
        return 0;
    }
  • 相关阅读:
    改造二叉树
    汽车加油行驶问题
    [SHOI2012]回家的路
    子串
    P3558 [POI2013]BAJ-Bytecomputer
    HDU
    UVALive
    ZOJ
    HDU
    牛客小白月赛2 题解
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3069968.html
Copyright © 2011-2022 走看看