poj 2762
http://poj.org/problem?id=2762
题意:给一个无向图,问对任意的两个点x,y,是否都存在一条路径从一个点出发到达另一个点。
思路:先用tarjan对无向图进行缩边和求弱连通分量,如果弱连通分量不为1,则No;然后重建无向图,判断是否是线树,是则Yes,否则No。
注意:缩边后的图不一定是棵标准的树。

#include<stdio.h> #include<string.h> #include<stdlib.h> #include<iostream> #include<stack> #include<utility> #include<vector> using namespace std; const int maxn = 1005; struct nd { int from,to,next; }edge[maxn*6]; int head[maxn],ecnt,idx,cnt; int vis[maxn],dfn[maxn],low[maxn]; int dgr[maxn],belong[maxn]; stack<int>st; void add(int s,int t) { edge[ecnt].from = s; edge[ecnt].to = t; edge[ecnt].next = head[s]; head[s] = ecnt++; } void tarjan(int u) { int i,v; 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]){ tarjan(v); low[u] = min(low[v],low[u]); }else if(vis[v]) low[u] = min(dfn[v],low[u]); } if(dfn[u] == low[u]) { cnt++; do{ v = st.top(); st.pop(); vis[v] = 0; belong[v] = cnt; }while(v!=u); } } int dfs(int cur) { int i,j,k = 0,v; for(i = head[cur]; i != -1; i = edge[i].next) { j = edge[i].to; dgr[j]--; if(!dgr[j]){k++; v = j;} if(k>1)return 1; } if(k) return dfs(v); return 0; } int main() { int i,j,k,t,n,m,u,v; scanf("%d",&t); while(t--) { scanf("%d %d",&n,&m); memset(belong,0,sizeof(belong)); memset(head,-1,sizeof(head)); memset(dgr,0,sizeof(dgr)); memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); ecnt = 0; idx = 0; cnt = 0; for(i = 0; i < m; ++ i) { scanf("%d %d",&u,&v); add(u,v); } for(i = 1; i <= n; ++ i) if(!dfn[i])tarjan(i); k = ecnt; ecnt = 0; memset(head,-1,sizeof(head)); for(i = 0; i < k; ++ i) { u = belong[edge[i].from]; v = belong[edge[i].to]; if(u!=v){ add(u,v); dgr[v]++; } } k = 0; for(i = 1; i <= cnt; ++ i) if(!dgr[i]){k++;j = i;} if(k!=1){puts("No"); continue;} k = dfs(j); if(!k)puts("Yes");else puts("No"); } return 0; }