哆啦B梦的传送门
题意:给出几条单向边,问你可以构成几个强连通量!
分析:tarjan模板时,需要标记每个点属于哪个强连通分量。完了要遍历每一条边,如果有一条边的两个点不属于通一个强连通分量,就把终点标记上,代表入度。最后遍历有几个入度为0的点,代表强连通量的数量。
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int num,n,m,top,sum,ans;
int ins[10010],low[10010],dfn[10010],stack[10010];
int next[10010],head[10010],in[10010],shu[10010];
int a[1010][1010];
struct node
{
int v,next;
}e[1000010];
void add(int u,int v)
{
num++;
e[num].v=v;
e[num].next=head[u];
head[u]=num;
}
void dfs(int u)
{
int x,i;
stack[top++]=u;
low[u]=dfn[u]=sum++;
ins[u]=1;
for(i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v])
low[u]=min(low[v],low[u]);
}
if(dfn[u]==low[u])
{
ans++;
do
{
x=stack[--top];
shu[x]=ans;
ins[x]=0;
}while(x!=u);
}
}
void tarjan()
{
int i;
memset(ins,0,sizeof(ins));
memset(dfn,0,sizeof(dfn));
ans=0;
top=0;
sum=0;
for(i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
}
int main()
{
int i,x,y,j,ss;
scanf("%d",&n);
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==1)
add(i,j);
}
tarjan();
ss=0;
for(i=1;i<=n;i++)//遍历每一条边
for(j=1;j<=n;j++)
{
if(shu[i]!=shu[j]&&a[i][j]==1)
in[shu[j]]++;//终点入度
}
for(i=1;i<=ans;i++)//按照强连通分量点去查找,相当于缩点了
if(!in[i])
ss++;
printf("%d\n",ss);
}