题目链接:
题目大意:
给出一些牛,他们之间有崇拜关系,且这种关系具有传递性,问被所有其他牛崇拜的牛的个数
题目分析:
首先对于这个有向图,它的所有强连通分量中的点都是互相崇拜的,那么我们先进行缩点,并且记录每个强连通分量的大小,也就是点的个数,然后得到了一张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 );
}
}