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\n", a);

    

    if(cnt == 2)

        printf("0\n");

    else

        printf("%d\n", 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;

}

 

你可能感兴趣的:(NetWork)