poj 1236 Network of Schools(强连通分量缩点)

题目链接:

点击打开链接

题目大意:

给出一个网络,问最少向几个点发布信息,才能传播到整张图,第二问问最少添加多少条边,能将这个这个图变成一个强连通图

题目分析:

首先第一问,一定要先强连通缩点,强连通分量当中的点可以相互到达,然后得到一个dag(有向无环联通图)图,所以只需判断新的图,有几个点入度为0即可

那么第二问,就是在这个DAG图中,只要所有点都有入度和出度即可,就是可以被其他点到达,也可以到达其他点,这样一定是一个强连通分量,(因为之前的图不存在环)

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#define MAX 107

using namespace std;

int dfn[MAX],low[MAX],b[MAX];
int mark[MAX];
int times,cnt;

vector e[MAX];
stack s;

void tarjan ( int u )
{
    dfn[u] = low[u] = ++times;
    mark[u] = 1;
    s.push ( u );
    int len = e[u].size();
    for ( int i = 0 ; i < len ; i++ )
    {
        int v = e[u][i];
        if (!mark[v])
        {
            tarjan ( v );
            low[u] = min ( low[u] , low[v] );
        }
        if (mark[v] == 1 )
            low[u] = min ( low[u] , dfn[v] );
    }
    if ( dfn[u] == low[u] )
    {
        int temp;
        do
        {
            temp = s.top();
            b[temp] = cnt;
            mark[temp] = 2;
            s.pop();
        }while ( temp != u );
        cnt++;
    }
}

void init ()
{
    for ( int i = 0 ; i < MAX ; i++ )
        e[i].clear();
    while ( !s.empty()) s.pop();
    times = cnt = 0;
}

int n;
int in[MAX],out[MAX];

int main ()
{
    while (~scanf ( "%d" , &n ) )
    {
        init();
        int x;
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d" , &x );
            while ( x )
            {
                e[i].push_back(x);
                scanf ("%d" , &x );
            }
        }

        memset ( mark , 0 , sizeof ( mark ));
        for ( int i = 1 ; i <= n ; i++ )
            if ( !mark[i] ) tarjan ( i );

        //cout << cnt << endl;

        if ( cnt == 1 )
        {
            puts ( "1\n0");
            continue;
        }

        memset ( in , 0 , sizeof ( in ));
        memset ( out , 0 , sizeof ( out ));
        int ans1,ans2;
        ans1 = ans2 = 0;
        for ( int i = 1 ; i <= n ; i++ )
        {
            int len = e[i].size();
            for ( int j = 0 ; j < len ; j++ )
            {
                if (b[e[i][j]] == b[i] ) continue;
                in[b[e[i][j]]]++;
                out[b[i]]++;
            }
        }


       /* cout << "blocks :" << endl;
        for ( int i = 1 ; i <= 5 ; i++ )
            cout << b[i] << " ";
        cout << endl;*/
        for ( int i = 0 ; i < cnt ; i++ )
        {
            //cout << in[i] << "   " << out[i] << endl;
            if ( !in[i] ) ans1++;
            if ( !out[i] ) ans2++;
        }

        printf ( "%d\n%d\n" , ans1 , max ( ans1 , ans2 ));
    }
}


你可能感兴趣的:(C++,图论,tarjan,强连通分量缩点)