Network of Schools POJ - 1236(强连通+缩点)

题目大意

    有N个学校,这些学校之间用一些单向边连接,若学校A连接到学校B(B不一定连接到A),那么给学校A发一套软件,则学校B也可以获得。现给出学校之间的连接关系,求出至少给几个学校分发软件,才能使得所有的学校均可以获得软件;以及,至少需要添加几条单向边连接学校,才能使得给这些学校中任何一所发软件,其余的学校均可以收到。

题目分析

    在一个图中,强连通分支内的任何一个点被“发软件”,则分支内的所有点均可以获得,因此首先求出强连通分支,将强连通分支合并为一点来看。 
    重构之后的图若只有一个点,则只需要向任何一所学校发送即可。即结果为1(至少向1所学校发布软件) 0(不需要添加新边来使得整个图连通). 
    重构之后的图若有多个点,则考虑这些点中入度为0的点:入度为0的点不能被其他点到达,而一个入度不为0的点可以从某个入度为0的点到达,那么只需要向这些入度为0的点分发软件,就可以使得所有的点均能获得软件。 
    重构之后的图中有出度为0的点,在图中,入度为0的点(设为m个)无法从其他点到达,那么为了使得所有的点连通,需要m条路径连接到这m个入度为0的点;而出度为0的点(设为n个)无法到达其他点,那么为了使得所有的点连通,需要n条路径从这n个出度为0的点连出。于是,至少需要添加 max(m, n)条边,使得图中所有的点的入度和出度不为0. 
    同时,在一个有向无环图中,如果该图的所有点均可连接到一块,且每个点的出度和入度均不为0,则该图肯定强连通。于是,结果为 max(m,n)

题意转自:https://www.cnblogs.com/gtarcoder/p/4871267.html

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <stack>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 150000, INF = 0x7fffffff;
vector<int> G[maxn];
int pre[maxn], lowlink[maxn], sccno[maxn];
int in[maxn], out[maxn];
int dfs_clock, scc_cnt, n;
stack<int> s;

void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    s.push(u);
    for(int i=0; i<G[u].size(); i++)
    {
        int v = G[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }
        else if(!sccno[v])
            lowlink[u] = min(lowlink[u], pre[v]);
    }
    if(lowlink[u] == pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x = s.top(); s.pop();
            sccno[x] = scc_cnt;
            if(x == u) break;
        }
    }
}

void calcu()
{
    int t1 = 0, t2 = 0;
    mem(in, 0);
    mem(out, 0);
    dfs_clock = scc_cnt = 0 ;
    mem(sccno, 0);
    mem(pre, 0);
    for(int i=1; i<=n; i++)
        if(!pre[i])
            dfs(i);
    for(int i=1; i<=n; i++)
        for(int j=0; j<G[i].size(); j++)
            if(sccno[i] != sccno[G[i][j]])
                out[sccno[i]]++, in[sccno[G[i][j]]]++;
    for(int i=1; i<=scc_cnt; i++)
    {
        if(in[i] == 0)
            t1++;
        if(out[i] == 0)
            t2++;
    }
    if (scc_cnt == 1) printf("1\n0\n");
    else
        printf("%d\n%d\n",t1,max(t2,t1));


}

int main()
{
    cin>> n;
    for(int i=1; i<=n; i++)
    {
        for(;;)
        {
            int v;
            cin>> v;
            if(v == 0) break;
            G[i].push_back(v);

        }
    }
    calcu();

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WTSRUVF/p/9301096.html
今日推荐