题目地址: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; }
原文地址:http://blog.csdn.net/u013486414/article/details/46481647