2 4 0 1 1 2 2 0 2 3 3 2 0 0 4 0 1 1 2 2 3 3 0 1 3 0 0题意:1:强连通图
2:图中每条边只处于一个环内
怎么样判断一个边只在一个环内呢?其实在没有找到一个环之前的时候,有一个DFS的过程,在这个过程中每走到一个点,我们就记录一下它是有哪一个点走下来的 也就是这个点的上一层的点,等到我们找到环的时候,我们马上返回去查找,查找那个点是 out了两次以上,那么肯定有边处于两个或者两个以上环内,就不符合了
#include"stdio.h" #include"string.h" #include"queue" #include"stack" #include"iostream" #include"stdlib.h" #define M 20005 #define inf 999999999 using namespace std; stack<int>q; int head[M],dfn[M],low[M],use[M],belong[M],pre[M],sum[M],flag1; int num,index,t,n; struct st { int u,v,next; }edge[M*3]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++; } void tarjan(int u) { int i; dfn[u]=low[u]=++index; q.push(u); use[u]=1; for(i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { pre[v]=u; tarjan(v); low[u]=min(low[u],low[v]); } else if(use[v]) { low[u]=min(low[u],dfn[v]); for(int j=u;j!=v;j=pre[j])//当发现后向边指向祖先点的时候, //就顺着环向上查找,把点记录在sum++中,若有点被记录了两次 //或两次以上,则返回,肯定有边至少在两个环内; { sum[j]++; if(sum[j]>1) { flag1++; break; } } } } if(dfn[u]==low[u]) { num++; int vv; do { vv=q.top(); q.pop(); use[vv]=0; belong[vv]=num; }while(vv!=u); } } void solve() { num=index=0; int i; memset(belong,-1,sizeof(belong)); memset(dfn,0,sizeof(dfn)); memset(use,0,sizeof(use)); memset(pre,0,sizeof(pre)); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } } int main() { int T,i; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); int x,y; while(scanf("%d%d",&x,&y),x||y) { x++; y++; add(x,y); } flag1=0; solve(); int flag=0; for(i=1;i<=n;i++) { if(belong[i]!=belong[1]) { flag++; break; } } if(flag) printf("NO\n"); else { if(flag1) printf("NO\n"); else printf("YES\n"); } } }