具体算法:http://hi.baidu.com/z917912363/item/a489943f63b27a5680f1a777
http://acm.hdu.edu.cn/showproblem.php?pid=1269
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; struct{ int to,next; }edge[100005]; //边结点数组 int head[10010],stack[10010],DFN[10010],Low[10010],Belong[100010]; // head[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组 // Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号 int instack[10010],cnt,scnt,top,n,tot; // instack[]为是否在栈中的标记数组 void Add(int x,int y){ //构建邻接表 edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot++; } void Tarjan(int v) //Tarjan算法求有向图的强连通分量 { int min,i,t,j; DFN[v]=Low[v]=++cnt; //cnt为次序计数器 instack[v]=1; //标记在栈中 stack[top++]=v; //入栈 for(i=head[v];i!=-1;i=edge[i].next){ //枚举v的每一条边 j=edge[i].to; //v所邻接的边 if(!DFN[j]){ //未被访问 Tarjan(j); //继续向下找 if(Low[v]>Low[j])Low[v]=Low[j]; // 更新结点v所能到达的最小次数层 }else if(instack[j]&&DFN[j]<Low[v]){ //如果j结点在栈内, Low[v]=DFN[j]; } } if(DFN[v]==Low[v]){ //如果节点v是强连通分量的根 scnt++; //连通分量标号加1 do{ t=stack[--top]; //退栈 instack[t]=0; //标记不在栈中 Belong[t]=scnt; //出栈结点t属于cnt标号的强连通分量 }while(t!=v); //直到将v从栈中退出 } } void Slove(){ int i; scnt=cnt=top=0; //初始化连通分量标号,次序计数器,栈顶指针为0 memset(DFN,0,sizeof(DFN)); //结点搜索的次序编号数组为0,同时可以当是否访问的数组使用 for(i=1;i<=n;i++) //枚举每个结点,搜索连通分量 if(!DFN[i]) //未被访问 Tarjan(i); //则找i结点的连通分量 } int main(){ int m,i,x,y; while(scanf("%d%d",&n,&m),n+m){ memset(head,-1,sizeof(head)); //邻接表的头结点数组初始化为-1 while(m--){ scanf("%d%d",&x,&y); Add(x,y); } Slove(); //求强连通分量 if(scnt==1) //只有一个强连通分量,说明此图各个结点都可达 printf("Yes "); else printf("No "); } }