题意:
一幅有向图是不是仙人掌
思路:
有向图仙人掌是强连通图且每条边最多只属于一个环
一幅有向图是仙人掌当且仅当满足3个条件:
1、dfs树无横向边
2、对于节点u的所有儿子v,它们的low[v]<=dfn[u]
3、满足low[v]<dfn[u]的v的数量num(v),u的逆向边的数量num(u),有如下关系num(v)+num(u)<2
证明见 http://download.csdn.net/detail/kksleric/4502360
代码:
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<map> #include<set> #include<vector> using namespace std; typedef __int64 LL; #define N 20010 #define M 50010 #define inf 2147483647 int t,n,tot,idx; int head[N],dfn[N],low[N],instack[N]; struct edge { int v,next; }ed[M]; bool ans; void add(int u,int v) { ed[tot].v=v; ed[tot].next=head[u]; head[u]=tot++; } void tarjan(int u) { int i,v,num=0; dfn[u]=low[u]=++idx; instack[u]=1; for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(dfn[v]==-1) { tarjan(v); low[u]=min(low[u],low[v]); } else { if(instack[v]) low[u]=min(low[u],dfn[v]); else ans=false; } } for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(dfn[v]<dfn[u]) num++; else { if(low[v]>dfn[u]) ans=false; else if(low[v]<dfn[u]) num++; } } if(num>1) ans=false; } void solve() { ans=true; idx=0; memset(dfn,-1,sizeof(dfn)); memset(instack,0,sizeof(instack)); tarjan(0); for(int i=1;i<n;i++) if(dfn[i]==-1) ans=false; } int main() { int i,u,v; scanf("%d",&t); while(t--) { tot=0; memset(head,-1,sizeof(head)); scanf("%d",&n); while(~scanf("%d%d",&u,&v)) { if(!u&&!v) break; add(u,v); } solve(); if(ans) puts("YES"); else puts("NO"); } return 0; }
原文地址:http://blog.csdn.net/houserabbit/article/details/38870179