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;
}

 

posted @ 2015-04-27 17:25  向前走丶不回首  阅读(129)  评论(0编辑  收藏  举报