题目地址:HDU 1269
一道强连通分量的裸题,当只有一个强连通分量的时候输出Yes,否则输出No
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const double pi= acos(-1.0);
const double esp=1e-6;
const int maxn=10010;
const int maxm=100010;
int head[maxn],dfn[maxn],low[maxn],belong[maxm],stak[maxn],instack[maxn];
//stak[]模拟栈,dfn[]深搜次序数组,low[]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号
//belong[]每个结点所对应的强连通分量标号数组,instack[]为是否在栈中的标记数组
int cnt,index,top,ans;
struct node
{
int u,v;
int next;
}edge[maxm<<1];
void Init()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
cnt=0;
ans=top=index=0;//初始化连通分量标号,次序计数器,栈顶指针为0
}
void add(int u,int v)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void tarjan(int u)//tarjan算法求有向图的强连通分量
{
dfn[u]=low[u]=++index;
instack[u]=1; //标记在栈中
stak[top++]=u;//入栈
for(int i=head[u];i!=-1;i=edge[i].next){//枚举u的每一条边
int v=edge[i].v;//u所邻接的边
if(!dfn[v]){//未被访问
tarjan(v);//继续向下找
low[u]=min(low[u],low[v]); //更新结点u所能到达的最小次数层
}
else if(instack[v]){//如果v结点在栈内
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){//如果节点u是强连通分量的根
ans++;//连通分量标号加1
while(1){
int v=stak[top--];//退栈
instack[v]=0;//标记不在栈中
belong[v]=ans;//出栈结点v属于时间戳标号的强连通分量
if(u==v) break;
}
}
}
int main()
{
int n,m;
int u,v;
while(~scanf("%d %d",&n,&m)){
if(!n&&!m) break;
Init();
while(m--){
scanf("%d %d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++){//枚举每个结点,搜索连通分量
if(!dfn[i])//未被访问
tarjan(i);//则找i结点的连通分量
}
if(ans==1)
puts("Yes");
else
puts("No");
}
return 0;
}