有向图的tarjan算法
在一个强连通分量中的点可以相互传递 在强连通分量之间建边入度为零的强连通分量需要传递,统计个数即可
# include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1010,M=N*N;
int n;
int h[N], e[M], ne[M], idx;
int din[N];
int dfn[N], low[N], timestamp; // 时间戳
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt; // 每个点所属分量编号
void add(int a, int b) // 添加一条边a->b
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u, in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j])
low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
++ scc_cnt;
int y;
do {
y = stk[top -- ];
in_stk[y] = false;
id[y] = scc_cnt;
} while (y != u);
}
}
signed main()
{
memset(h, -1, sizeof h);
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int x;
cin>>x;
if(x==1)
add(i,j);
}
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
//cout<<scc_cnt<<endl;
for(int i=1;i<=n;i++)
{
for(int j=h[i];j!=-1;j=ne[j])
{
int k=e[j];
if(id[i]!=id[k])
din[id[k]]++;
}
}
int sum=0;
for(int i=1;i<=scc_cnt;i++)
{
if(din[i]==0)
sum++;
}
cout<<sum;
}