题目:http://poj.org/problem?id=2762
题意:给出n个山洞,对于每个山洞,如果任意选择两点s,e,都满足s可以到达e或者e可以到达s,则输出Yes,否则输出No。
分析:实际上判断是否弱连通,所以首先强连通,然后缩点,对缩点形成的图最多只能有一个入度为0的点,如果有多个入度为
0的点,则这两个连通分量肯定是不连通的。缩点后形成的图形是一棵树,入度为0的点是这颗树的根,这棵树只能是单链,不
能有分叉,如果有分叉,则这些分叉之间是不可达的,所以就对这棵树进行DFS,如果是单链则是YES。
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 10005; struct Edge { int to; Edge *next; }; Edge *map1[N],*map2[N]; //分别保存原图和缩点后的图 int dfn[N],low[N],stack[N],belong[N],indeg[N]; int index,scc_num,top; bool tmp[N]; int result[N]; void Tarjan(int u) { dfn[u] = low[u] = ++index; stack[++top] = u; tmp[u] = true; for(Edge *p = map1[u]; p; p = p->next) //枚举每一条边 { int v = p->to; if(!dfn[v]) { Tarjan(v); //dfs继续下找 low[u] = min(low[u],low[v]); } else if(tmp[v]) { low[u] = min(low[u],dfn[v]); } } if(low[u] == dfn[u]) //如果节点u是强连通分量的根 { int t; ++scc_num; //强连通分量个数加1 do { t = stack[top--]; tmp[t] = false; belong[t] = scc_num; //记录属于第几个强连通分量 } while(t != u); } } int Count(int n) { for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); return scc_num; } int Find() //在新图中找入度为0的点,如果只有一个就返回位置,否则返回0 { int record; int cnt = 0; for(int i=1; i<=scc_num; i++) { if(indeg[i] == 0) { cnt++; record = i; } } if(cnt == 1) return record; return 0; } bool TopSort() { int u,num = 0; while(u = Find()) { result[num++] = u; indeg[u] = -1; Edge *p = map2[u]; while(p) { indeg[p->to]--; p = p->next; } } if(num == scc_num) return true; return false; } void Init() { index = 0; top = 0; scc_num = 0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(indeg,0,sizeof(indeg)); memset(tmp,false,sizeof(tmp)); memset(map1,NULL,sizeof(map1)); memset(map2,NULL,sizeof(map2)); memset(result,0,sizeof(result)); } int main() { int T,m,n; scanf("%d",&T); while(T--) { Init(); scanf("%d%d",&n,&m); while(m--) { int a,b; scanf("%d%d",&a,&b); Edge *p = new Edge(); p->to = b; p->next = map1[a]; map1[a] = p; } int cnt = Count(n); if(cnt == 1) { puts("Yes"); continue; } for(int i=1;i<=n;i++) { Edge *p = map1[i]; while(p) { if(belong[i] != belong[p->to]) { indeg[belong[p->to]]++; Edge *q = new Edge(); q->to = belong[p->to]; q->next = map2[belong[i]]; map2[belong[i]] = q; } p = p->next; } } bool flag = false; int ans = 0; for(int i=1;i<=cnt;i++) { if(indeg[i] == 0) ans++; } if(ans > 1) flag = false; else if(TopSort()) flag = true; if(flag) puts("Yes"); else puts("No"); } return 0; }