LOJ-10094(强连通分量)
题目链接:传送门
思路:
先缩点,然后统计入度为0的点即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1e6+10; int num[maxn],low[maxn],tim,col,co[maxn]; int head[maxn],next[maxn],ver[maxn],tot; int st[maxn],top,in[maxn]; int MIN(int x,int y) { return x<y?x:y; } void Init() { memset(num,0,sizeof(num)); memset(low,0,sizeof(low)); memset(head,0,sizeof(head)); memset(next,0,sizeof(next)); memset(ver,0,sizeof(ver)); memset(co,0,sizeof(co)); tot=0;tim=0;col=0;top=0; } void addedge(int x,int y) { ver[++tot]=y;next[tot]=head[x];head[x]=tot; } void Tarjan(int u) { int v,i; low[u]=num[u]=++tim; st[++top]=u; for(i=head[u];i;i=next[i]){ v=ver[i]; if(!num[v]){ Tarjan(v); low[u]=MIN(low[u],low[v]); } else if(!co[v]) low[u]=MIN(low[u],num[v]); } if(low[u]==num[u]){ col++; co[u]=col; while(st[top]!=u){ co[st[top]]=col; top--; } top--; } } int main(void) { int n,i,j,x; scanf("%d",&n); Init(); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ scanf("%d",&x); if(x) addedge(i,j); } } for(i=1;i<=n;i++) if(!num[i]) Tarjan(i); for(i=1;i<=n;i++){ for(j=head[i];j;j=next[j]){ if(co[i]!=co[ver[j]]) in[co[ver[j]]]++; } } int cnt=0; for(i=1;i<=col;i++) if(in[i]==0) cnt++; printf("%d\n",cnt); return 0; }