poj 3180 The Cow Prom
http://poj.org/problem?id=3180
题意:给一个无向图,求出节点数据大于1的边通分量有多少个。
思路:直接tarjan缩点统计。

#include<stdio.h> #include<string.h> #include<stdlib.h> #include<stack> #include<iostream> #include<utility> using namespace std; const int maxn = 10005; struct nd { int v,next; }edge[maxn*5]; int head[maxn],vis[maxn],dfn[maxn],low[maxn],c[maxn]; int ecnt,idx,cnt,n,m; stack<int>st; void add(int u,int v) { edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } void tarjan(int u) { int i,v; dfn[u] = low[u] = ++idx; st.push(u); vis[u] = 1; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; 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; c[cnt]++; }while(v!=u); } } int main() { int i,j,k,u,v,w; while(scanf("%d %d",&n,&m)==2) { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(c,0,sizeof(c)); ecnt = idx = 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 = 0; for(i = 1; i <= cnt; ++ i) if(c[i]>1)k++; printf("%d\n",k); } return 0; }