#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<vector> using namespace std; const int maxn=50010; int first[maxn],to[maxn],next[maxn],cnt,from[maxn]; void add(int u,int v) { from[++cnt]=u; to[cnt]=v; next[cnt]=first[u]; first[u]=cnt; } int dfn[maxn],low[maxn],vis[maxn],ind,scc,now,st[maxn],top; int isc[maxn]; vector<int> bl[maxn]; int blc; int tag[maxn]; void Tarjan_dfs(int x,int fa) { int son=0; low[x]=dfn[x]=++ind; for(int i=first[x];i;i=next[i]) { int now=to[i]; if(!dfn[now]) { st[++top]=i;son++; Tarjan_dfs(now,x); low[x]=min(low[x],low[now]); if(low[now]>=dfn[x]) { isc[x]=1; bl[++blc].clear(); while(1) { int num=st[top--]; if(tag[from[num]]!=blc) { bl[blc].push_back(from[num]); tag[from[num]]=blc; } if(tag[to[num]]!=blc) { bl[blc].push_back(to[num]); tag[to[num]]=blc; } if(to[num]==now && from[num]==x)break; } } } else if(dfn[now]<dfn[x] && now!=fa) { st[++top]=i; low[x]=min(low[x],dfn[now]); } } if(fa==0 && son==1)isc[x]=0; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } for(int i=1;i<=n;i++)if(!dfn[i])Tarjan_dfs(i,-1); cout<<blc<<endl; return 0; }
来自韩棒棒,输出点双的数量
#include<cstdio> #include<vector> #include<algorithm> using namespace std; int n,m,order; int low[20004],dfn[20004],father[20004],son[20004]; //father:父结点 son:子结点个数 vector<int> edge[20004]; vector< pair<int,int> > cutedge; void tarjan(int u) { dfn[u]=low[u]=++order; for (int i=0;i<edge[u].size();i++) { int v=edge[u][i]; if(!dfn[v]) { son[u]++; father[v]=u; tarjan(v); if(low[v]>dfn[u]) cutedge.push_back(make_pair(min(v,u),max(v,u))); //边v-u为割边 low[u]=min(low[u],low[v]); } else if(v!=father[u]) low[u]=min(low[u],dfn[v]); } //根节点若有两棵或两棵以上的子树则该为割点 //非根节点若所有子树节点均没有指向u的祖先节点的回边则为割点 } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); edge[u].push_back(v),edge[v].push_back(u); } tarjan(1); sort(cutedge.begin(),cutedge.end()); for(int i=0;i<cutedge.size();i++) printf("%d %d ",cutedge[i].first,cutedge[i].second); }
输出桥,边双就是图删去桥后的联通块