poj 2186 Popular Cows(强连通分量缩点+dfs)

题目链接:

点击打开链接

题目大意:

给出一些牛,他们之间有崇拜关系,且这种关系具有传递性,问被所有其他牛崇拜的牛的个数

题目分析:

首先对于这个有向图,它的所有强连通分量中的点都是互相崇拜的,那么我们先进行缩点,并且记录每个强连通分量的大小,也就是点的个数,然后得到了一张DAG图,对于这张DAG图,我们反向建边,因为这个连通图一定无环,所以我们利用树形dp的思想,直接统计当前点的子树中点的总数即可,最后判断某个点的被崇拜的个数是不是n-1即可,如果是直接通过联通块计算的话,那么就是等于n,因为崇拜的牛中算上了它本身

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <stack>
#include <map>
#define MAX 10007

using namespace std;

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

typedef pair<int,int> pii;

vector<int> e[MAX<<4];
vector<int> edge[MAX<<4];
stack<int> s;
map<pii,bool> mp;

int sum[MAX],in[MAX];

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;
            sum[cnt]++;
            mark[temp] = 2;
            s.pop();
        }while ( temp != u );
        cnt++;
    }
}

void init ()
{
    memset ( mark , 0 , sizeof ( mark ));
    times = cnt = 0;
    for ( int i = 0 ; i < MAX ; i++ )
    {
        e[i].clear();
        edge[i].clear();
    }
    memset ( sum , 0 , sizeof ( sum ));
    memset ( in , 0 , sizeof ( in ));
    while ( !s.empty()) s.pop();
    times = cnt = 0;
    mp.clear();
}

void dfs ( int u , int p )
{
    int len = edge[u].size();
    in[u] = 1;
    for ( int i = 0 ; i < len ; i++ )
    {
        int v = edge[u][i];
        if ( v == p ) continue;
        if ( in[v] )
            sum[u] += sum[v];
        else
        {
            dfs ( v , u );
            sum[u] += sum[v];
        }
    }
}

int main ()
{
    int u ,v;
    while ( ~scanf ( "%d%d" , &n , &m ) )
    {
        while ( m-- )
        {
            scanf ( "%d%d" , &u , &v );
            e[u].push_back ( v );
        }

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

        /*puts("blocks: ");
        for ( int i = 1 ; i <= n ; i++ )
            printf ( "%d " , b[i] );
        puts("");*/

        for ( int i = 1 ; i <= n ; i++ )
        {
            int len = e[i].size();
            for ( int j = 0 ; j < len ; j++ )
            {
                int v = e[i][j];
                if ( b[v] == b[i] ) continue;
                if ( mp[make_pair(b[v],b[i])]) continue;
                mp[make_pair(b[v],b[i])] = true;
                edge[b[v]].push_back ( b[i] );
            }
        }

       /* puts( "indegree");
        for ( int i = 0 ; i < cnt ; i++ )
            printf ( "%d " , in[i] );
        puts(" ");*/


        for ( int i = 0 ; i < cnt ; i++ )
            if ( !in[i] ) dfs ( i , -1 );

       /* puts("sum : ");
        for ( int i = 0 ; i < cnt ; i++ )
            printf ( "%d " , sum[i] );
        puts("");*/

        int ans = 0;
        for ( int i = 1 ; i <= n ; i++ )
            if ( sum[b[i]] == n ) ans++;

        printf ( "%d\n" , ans );
    }
}


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