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

     题目大意:

    给定一个有向图,求:
    1) 至少要选几个顶点,才能做到从这些顶点出
       发,可以到达全部顶点
    2) 至少要加多少条边,才能使得从任何一个顶
     点出发,都能到达全部顶点
       顶点数<= 100

    有用的定理:

    有向无环图中所有入度不为0的点,一定可以由某个入度为0的点出发可达。由于无环,所以从任何入度不为0的点往回走必然终止于一个入度为0的点

    解题思路:

    1. 求出所有强连通分量

    2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。

    3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少

    在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少

     加边的方法:要为每个入度为0的点添加入边,为每个出度为0的点添加出边假定有 n 个入度为0的点,m个出度为0的点,max(m,n)就是第二个问题的解(证明难,略)

    当我们求出强联通分量之后就可以,然后重新构图, 最后得出结果, 有一个答案要特殊判断一下, 因为只有一个强联通分量的时候是不需要多加边,因此要特殊判断一下。

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <stack>
    #include <cstring>
    using namespace std;
    #define INF 0xfffffff
    #define maxn 106
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    stack<int> S;
    bool inStack[maxn];
    int low[maxn],dfn[maxn], n, time, belong[maxn], cnt;
    bool G[maxn][maxn];
    
    void init()
    {
        memset(inStack, false, sizeof(inStack));
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(G, false, sizeof(G));
        memset(belong, 0, sizeof(belong) );
        cnt = time = 1;
    }
    void tarjan(int u)
    {
        low[u] = dfn[u] = time ++;
        S.push(u);
        inStack[u] = true;
        int i, v;
        for(i=1; i<=n; i++)
        {
            if(!G[u][i])
                continue;
            
            if( !low[i])
            {
                tarjan(i);
                low[u] = min(low[u], low[i]);
            }
            else if( inStack[i] )
            {
                low[u] = min(low[u], dfn[i]);
            }
        }
        
        if(low[u] == dfn[u])
        {
            do
            {
                v = S.top();
                S.pop();
                inStack[v] = false;
                belong[v] = cnt;
            }
            while(u != v);
            cnt ++;
        }
    }
    void solve()
    {
        int in[maxn] = {0}, out[maxn] = {0}, a, b;
        bool maps[maxn][maxn] = {0};
        int i, j;
        for(i=1; i<=n; i++)
        {
            if(!low[i])
                tarjan(i);
        }
        
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
            {
                if(G[i ][j ] && belong[i] != belong[j])
                {
                    maps[belong[i] ][belong[j] ] = true;
                }
            }
        }
        a = b = 0;
        for(i=1; i<cnt; i++)
        {
            for(j=1; j<cnt; j++)
            {
                if(maps[i][j])
                {
                    in[j] ++;
                    out[i] ++;
                }
            }
        }
        
        for(i=1; i<cnt; i++)
        {
            if(in[i] == 0)
                a ++;
            if(out[i] == 0)
                b ++;
        }
        printf("%d
    ", a);
        
        if(cnt == 2)
            printf("0
    ");
        else
            printf("%d
    ", max(a,b) );
        
    }
    
    int main()
    {
        int i, a;
        while(scanf("%d",&n) != EOF)
        {
            init();
            for(i=1; i<=n; i++)
            {
                while(scanf("%d",&a), a)
                {
                    G[i][a] = true;
                }
            }
            
            solve();
        }
        return 0;
    }
  • 相关阅读:
    关于各种好玩的神奇函数
    模板——AC自动机
    模板——造数据
    VIM常用操作
    springboot注解
    面试题
    Linux常用命令
    Zookeeper
    对cpu与load的理解及线上问题处理思路
    top
  • 原文地址:https://www.cnblogs.com/chenchengxun/p/4460760.html
Copyright © 2011-2022 走看看