#include<bits/stdc++.h>
#define maxn 200000
#define P pair<int,int>
using namespace std;
vector<int> G[maxn];
vector<P> bridge;
int low[maxn],dfn[maxn];
bool iscut[maxn];
int cnt=0,n,m;
int tarjan(int x,int fa)//割点(割顶)
{
low[x]=dfn[x]=++cnt;
int child=0;
for(int i=0;i<G[x].size();i++)
{
int j=G[x][i];
if(!dfn[j])//如果没有访问过这个节点
{
child++;
tarjan(j,x);
low[x]=min(low[j],low[x]);//用后代的low更新x的low
if(low[j]>dfn[x]) bridge.push_back(P(x,j));
if(low[j]>=dfn[x])
iscut[x]=1;//如果这个节点是满足条件的,就是不能回到更祖先的节点
}
else if(dfn[j]<dfn[x]&&j!=fa)//注意j!=fa不能返回他的父节点
low[x]=min(low[x],dfn[j]);//用反向边进行更新
}
if(fa<0&&child==1) iscut[x]=0;//如果他是根节点,并且他的孩子等于1
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int t1,t2,t3;
cin>>t1>>t2;
G[t1].push_back(t2);
G[t2].push_back(t1);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i,-1);
vector<int> ans;
for(int i=1;i<=n;i++)
if(iscut[i])
ans.push_back(i);
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
cout<<ans[i]<<" ";
cout<<"\n";
sort(bridge.begin(),bridge.end());
for(int i=0;i<bridge.size();i++)
cout<<bridge[i].first<<" "<<bridge[i].second<<"\n";
return 0;
}
其实两个是一个道理的