Network of Schools---poj1236(强连通分量)

题目链接

题意:学校有一些单向网络,现在需要传一些文件

求:1,求最少需要向几个学校分发文件才能让每个学校都收到,

  2,需要添加几条网络才能从任意一个学校分发都可以传遍所有学校。

解题思路(参考大神的):

—        1. 求出所有强连通分量

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

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

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

加边的方法:

要为每个入度为0的点添加入边,为每个出度为0的点添加出边

假定有 n 个入度为0的点,m个出度为0的点,如何加边?

把所有入度为0的点编号 0,1,2,3,4 ....N -1

每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,

这需要加n条边

若 m <= n,则

加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边

若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。

所以,max(m,n)就是第二个问题的解

此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
#include <stack>
using namespace std;
#define INF 0xfffffff
#define N 10060
int Out[N],In[N], n;

int low[N], dfn[N], num, cnt, Time, vis[N], belong[N];
vector<int> G[N];
stack<int>sta;

void Init()
{
    Time=num=cnt=0;
    for(int i=0;i<=n;i++)
        G[i].clear();
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(vis, 0, sizeof(vis));
    memset(belong, 0, sizeof(belong));
    memset(Out, 0, sizeof(Out));
    memset(In, 0, sizeof(In));
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++Time;
    int len = G[u].size(), v;
    sta.push(u);
    vis[u] = 1;
    for(int i=0; i<len; i++)
    {
        v = G[u][i];
        if(dfn[v]==0)
        {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(vis[v]==1)
        {
            low[u] = min(dfn[v], low[u]);
        }
    }
    if(low[u]==dfn[u])
    {
        ++num;
        do
        {
            v = sta.top();
            belong[v] = num;// 缩点;
            sta.pop();
            vis[v] = 0;
        }while(u!=v);
    }
}
int main()
{
    int a, ans1, ans2, ans, u, v;
    while(scanf("%d", &n)!=EOF)
    {
        Init();

        for(int i=1; i<=n; i++)
        {
            while(scanf("%d", &a), a)
            {
                G[i].push_back(a);
            }
        }
        for(int i=1; i<=n; i++)
            if(!dfn[i])
                Tarjan(i);
        ans1 = ans2 = 0;
        for(int i=1; i<=n; i++)
        {
            int len=G[i].size();
            for(int j=0; j<len; j++)
            {
                u = belong[i]; v = belong[G[i][j]];
                if(u!=v)
                {
                    Out[u]++;
                    In[v]++;
                }
            }
        }
        for(int i=1; i<=num; i++)
        {
            if(Out[i]==0)ans2++;
            if(In[i]==0)ans1++;
        }
        ans = max(ans1, ans2);
        if(num==1)
            printf("1
0
");
        else
            printf("%d
%d
", ans1, ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhengguiping--9876/p/4708365.html