#include <stdio.h> #include <string.h> #include <vector> #include <stack> #include <algorithm> using namespace std; #define N 10005 stack<int>sta; vector<int>mp[N]; int dfn[N]; int low[N]; int InStack[N]; int indexx,number; int n, m; void tarjan(int u) { InStack[u] = 1; low[u] = dfn[u] = ++ indexx; sta.push(u); for (int i = 0; i < mp[u].size(); ++ i) { int t = mp[u][i]; if (dfn[t] == 0)//如果没有入过栈内, { tarjan(t);//把他遍历一边 low[u] = min(low[u], low[t]);//遍历完之后寻找他的子节点中low最小的 } else if (InStack[t] == 1)//如果他的某个节点在栈中, { low[u] = min(low[u], dfn[t]);//最早的时间戳就是他的所有子节点的最早时间 } } if (low[u] == dfn[u])//如果找到这两个时间戳相等,那么这个点是此联通图的开始那个点,退栈到u=v { ++ number;//表示有几个强连通图 while (!sta.empty()) { int v = sta.top(); sta.pop(); InStack[v] = 0;//把它标记为未在栈内 if (v == u) break; } } } int main() { //freopen("input.txt","r",stdin); while(scanf("%d%d",&n,&m),n+m) { memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(InStack, 0, sizeof(InStack)); indexx = number = 0; for (int i = 1; i <= n; ++ i) { mp[i].clear(); } while(!sta.empty()) sta.pop(); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); mp[a].push_back(b); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); if(number>1)//如果有多个连通图的话,那么此有向图肯定不是点两两连通 puts("No"); else puts("Yes"); } }
上图就是最后处理好之后的low 和dfn的值
比较注意的是3 4 的值
因为 自己手动模拟一下 匾额发现其中的奥秘
原文:http://blog.csdn.net/u013076044/article/details/41695701