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