1 #include<cstdio>
2 #include<cstring>
3 #include<vector>
4 #include<algorithm>
5 using namespace std;
6 vector<vector<int> > g;
7 int dfn[11000];//节点在dfs过程中的访问序号(也可以叫做开始时间)
8 int low[11000];//节点的子树中能够通过非父子边追溯到的最早的节点的dfs开始时间
9 int fa[11000];//dfs树中每个点的父节点
10 int viscv[11000];//标记是否为割点
11 int ntime;//dfs中记录时间
12 int n,m;//点数和边数
13 void tarjan(int u,int father)//father是u的父节点
14 {
15 fa[u]=father;
16 int i;
17 low[u]=dfn[u]=ntime++;
18 for(i=0;i<g[u].size();i++)
19 {
20 int v=g[u][i];
21 if(!dfn[v])
22 {
23 tarjan(v,u);
24 low[u]=min(low[u],low[v]);
25 }
26 else if(father!=v)
27 {
28 low[u]=min(low[u],dfn[v]);
29 }
30 }
31 }
32 void solve()
33 {
34 int sontree=0;//dfs树中根节点的子树的数目
35 int i;
36 tarjan(1,0);
37 for(i=2;i<=n;i++)
38 {
39 int v=fa[i];
40 if(v==1) sontree++;
41 else
42 {
43 if(dfn[v]<=low[i])
44 viscv[v]=1;
45 }
46 }
47 if(sontree>1) viscv[1]=1;
48 for(i=1;i<=n;i++)
49 {
50 if(viscv[i])
51 printf("%d\n",i);
52 }
53 for(i=1;i<=n;i++)
54 {
55 int v=fa[i];
56 if(v>0&&dfn[v]<low[i])
57 printf("%d %d\n",v,i);
58 }
59 }
60 int main()
61 {
62 int u,v,i;
63 ntime=1;
64 while(scanf("%d%d",&n,&m)!=EOF)
65 {
66 g.clear();
67 g.resize(11000);
68 ntime=1;
69 for(i=0;i<m;i++)//点编号是从1开始的
70 {
71 scanf("%d%d",&u,&v);
72 g[u].push_back(v);
73 g[v].push_back(u);
74 }
75 memset(dfn,0,sizeof(dfn));
76 memset(low,0,sizeof(low));
77 memset(fa,0,sizeof(fa));
78 memset(viscv,0,sizeof(viscv));
79 solve();
80 }
81 return 0;
82 }