hdu 3594 Cactus
http://acm.hdu.edu.cn/showproblem.php?pid=3594
这是一个很好的题目,很巧的利用的low[u]和dfn[u]。如果low[u]!=dfn[u],则说明已经存在环,如果我们访问u点时发现low[u]!=dfn[u],则说明有一条边在两个环上了。

#include<stdio.h> #include<string.h> #include<iostream> #include<stack> #include<algorithm> #include<utility> using namespace std; const int maxn = 20005; struct nd { int to,next; }edge[maxn*5]; int dfn[maxn],vis[maxn]; int flag[maxn],head[maxn]; int ecnt,cnt,idx,ok,low[maxn]; stack<int>st; void add(int s,int t) { edge[ecnt].to = t; edge[ecnt].next = head[s]; head[s] = ecnt++; } void tarjan(int u) { int i,v; if(ok)return; dfn[u] = low[u] = ++idx; vis[u] = 1; st.push(u); for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(dfn[v]==0){ tarjan(v); low[u] = min(low[v],low[u]); }else if(vis[v]){ low[u] = min(dfn[v],low[u]); if(dfn[v]!=low[v]) ok = 1; } if(ok)return; } if(dfn[u]==low[u]) { cnt++; if(cnt>1)ok=1; do{ v = st.top(); st.pop(); vis[v] = 0; }while(st.top()!=u); } } int main() { int i,j,s,t,n,cas; scanf("%d",&cas); while(cas--) { scanf("%d",&n); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(flag,0,sizeof(flag)); memset(dfn,0,sizeof(dfn)); ecnt = cnt = idx = 0; scanf("%d %d",&s,&t); while(s+t){ ++s; ++t; add(s,t); scanf("%d %d",&s,&t); } while(!st.empty()) st.pop(); ok = 0; for(i = 1; i <= n; ++ i)if(!dfn[i]) tarjan(i); if(ok||cnt!=1)puts("NO"); else puts("YES"); } return 0; }