首先转载ByVoid大神的日志一篇:http://www.byvoid.com/blog/scc-tarjan/
这个可以说是我看过最好的讲解tarjian算法的文章了,实例分析,带图片,非常有助于理解,这里请允许我代表我本人以及看过我的这篇博文的读者向THU ByVoid大神致以崇高的敬意!
下面转入正题,本题可以说是很明显的tarjian算法题目,如果说看不出来,这里提供一篇日志:http://blog.csdn.net/lyy289065406/article/details/6764104
不懂的看看这个就应该明白为什么用tarjian求strong connect component可以解决这个了。
基于以上两篇文章,我认为我没有任何必要写解题思路了:
不过,解决本体,有一个地方,很多人说,缩图之后进行dfs判断,其实这个是不需要的,只要记录所图后每个点的出度即可,如果出度为0的点>1,那么就可能没有形成树,或者即使形成树,但是叶子节点>1.所以答案为0.大家仔细想想,这样处理是肯定正确的。
下面是代码:
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
#include <vector>
#define maxn 10007
using namespace std;
int n, m, be[maxn], dfn[maxn], low[maxn];
int sum, t, in[maxn], out[maxn], ans;
bool v[maxn];
vector<int> e[maxn];
stack<int> stk;
void tarjan( int s )
{
int i, j;
dfn[s] = low[s] = ++t;
v[s] = true;
stk.push(s);
for ( i = 0; i < e[s].size(); i++ )
{
j = e[s][i];
if ( !dfn[j] )
{
tarjan(j);
if (low[s]>low[j]) low[s] = low[j];
}
else if ( v[j] && dfn[j]<low[s] )
low[s] = dfn[j];
}
if ( dfn[s]==low[s] )
{
do
{
j = stk.top();
v[j] = false;
be[j] = sum;
stk.pop();
}
while ( j != s );
sum++;
}
}
int main()
{
int i, j, k, a, b;
cin >> n >> m;
while ( !stk.empty() ) stk.pop();
for ( i = 0; i < n; i++ )
e[i].clear();
for ( i = 0; i < m; i++ )
{
scanf( "%d%d", &a, &b);
a--; b--;
e[a].push_back(b);
}
memset(dfn,0,sizeof(dfn));
memset(v,0,sizeof(v));
sum = t = 0;
for ( i = 0; i < n; i++ )
if ( !dfn[i] ) tarjan(i);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for ( i = 0; i < n; i++ )
for ( j = 0; j < e[i].size(); j++ )
if ( be[e[i][j]] != be[i] )
{
out[be[i]]++; in[be[e[i][j]]];
}
k = -1; ans = 0;
for ( i = 0; i < sum; i++ )
if ( out[i] == 0 )
{
if ( k != -1 ) break;
k = i;
}
if ( i < sum ) { printf( "0\n"); return 0; }
for ( i = 0; i < n; i++ )
if ( be[i] == k ) ans++;
printf( "%d\n", ans);
}