题意:就是判断一个图是否为弱连通图。
思路:先用tarjan处理一遍找出强连通分量。然后将每个强连通分量缩点,形成一个有向无环图。
如果该有向无环图是一个无分叉的树的话,即是弱连通图。
如果有分叉,则分叉两端的节点无法互相到达,即不是弱连通图。
#include<iostream>
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=1005,M=6005;
int n,m;
int edgehead[N];
struct Edge
{
int v,next;
}edge[M];
int indegree[N];
int outdegree[N];
bool instack[N];
int dfn[N],low[N];
int k=1;
void addedge(int u,int v)
{
edge[k].v=v;
edge[k].next=edgehead[u];
edgehead[u]=k++;
}
int stack[N];
int sp=0;
int index=0;
int headsta[N];
int ph=0;
int father[N];
void tarjan(int i)
{
dfn[i]=low[i]=++index;
instack[i]=true;
stack[sp++]=i;
for(int j=edgehead[i];j;j=edge[j].next)
{
int v=edge[j].v;
if(!dfn[v])
{
tarjan(v);
low[i]=min(low[i],low[v]);
}
else if(instack[v])
{
low[i]=min(low[i],dfn[v]);
}
}
if(dfn[i]==low[i])
{
headsta[ph++]=i;
int ans;
do
{
ans=stack[--sp];
father[ans]=i;
instack[ans]=false;
}while(ans!=i);
}
}
bool vis[N];
int sum;
bool dfs(int root,int w)
{
if(w==sum)
return true;
for(int i=edgehead[root];i;i=edge[i].next)
{
int v=edge[i].v;
if(father[v]!=father[root]&&!vis[v])
{
vis[v]=true;
return dfs(v,w+1);
}
}
return false;
}
void solve()
{
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=edgehead[i];j;j=edge[j].next)
{
if(father[edge[j].v]!=father[i])
{
indegree[father[edge[j].v]]++;
outdegree[father[i]]++;
}
}
}
sum=ph;
while(ph>0)
{
int now=headsta[--ph];
if(indegree[now]==0)
{
vis[now]=true;
if(dfs(now,1))
printf("Yes\n");
else
printf("No\n");
break;
}
}
}
int main()
{ int cases;
scanf("%d",&cases);
while(cases--)
{
k=1;
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(edge,0,sizeof(edge));
memset(edgehead,0,sizeof(edgehead));
memset(instack,0,sizeof(instack));
memset(headsta,0,sizeof(headsta));
memset(indegree,0,sizeof(indegree));
memset(outdegree,0,sizeof(outdegree));
memset(father,0,sizeof(father));
sp=0;
ph=0;
index=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int from,to;
scanf("%d%d",&from,&to);
addedge(from,to);
}
solve();
}
return 0;
}