题目链接:http://poj.org/problem?id=2186
题意:给你一些崇拜关系,崇拜关系可以传递(A->B, B->C, 则A->C),问有多少头牛是被其他所有牛都崇拜的,可以进行思考,一个强联通分量中,所有的牛都是被其他的牛崇拜的,也就是说我们可以先进行缩点,建立DAG图,然后建立好后,再思考,如果这个是一个联通的图,且只有一个出度为0的点的话,那么出度为0的点就是被其他所有的点所连接,也就是被所有的牛崇拜,反过来,如果出度为0的点不止一个,那么肯定不可能有点被其他所有的点连接,所以我们先判断一下就好。
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
const int N = 10005;
int n, m;
vector<int> g[N];
int Low[N], DFN[N], index, num, belong[N], val[N];
stack<int> S;
void Tarjan(int u)
{
DFN[u] = Low[u] = ++index;
S.push(u);
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(!DFN[v])
{
Tarjan(v);
Low[u] = min(Low[u], Low[v]);
}
else if(!belong[v])
Low[u] = min(Low[u], DFN[v]);
}
if(Low[u] == DFN[u])
{
num++;
int cnt = 0;
while(1)
{
cnt++;
int x = S.top(); S.pop();
belong[x] = num;
if (x == u) break;
}
val[num] = cnt;
}
}
void find_scc()
{
index = num = 0;
memset(DFN, 0, sizeof(DFN));
memset(belong, 0, sizeof(belong));
for(int i = 1; i <= n; i++)
if(!DFN[i])
Tarjan(i);
}
int out[N];
int main()
{
while(~scanf("%d%d", &n, &m))
{
int u, v;
while(m--)
{
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
find_scc();
memset(out, 0, sizeof(out));
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < g[i].size(); j++)
{
int v = g[i][j];
if(belong[i] != belong[v])
out[belong[i]]++;
}
}
int cnt = 0, ans;
for(int i = 1; i <= num; i++)
{
if(!out[i])
{
cnt++;
ans = val[i];
}
}
if(cnt > 1) ans = 0;
printf("%d\n", ans);
}
return 0;
}