#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
constexpr ll INF = 1001001001001001LL;
constexpr ll MOD = 1000000007LL;

// ?§?????????¨????????¨???????????????????¨???????????§???????
template <typename T>
struct Edge {
    int from, to;
    T cost;
    Edge(int s, T d) : to(s), cost(d) {}
    Edge(int f, int s, T d) : from(f), to(s), cost(d) {}

    bool operator<(const Edge &e) const {
        return cost < e.cost;
    }
    bool operator>(const Edge &e) const {
        return cost > e.cost;
    }
};

template <typename T>
using Graph = vector< vector< Edge<T> > >;

// ??¢??????????±??????? (artPoints)
// ???????±??????? (bridges)

// ??¢?????????????????????????????¨????????£?????§???????????£???????????????????????????????????¨
// ????????????????????????????????£?????§???????????£????????????????????????????????¨

template <typename T>
struct graphLink {
    vector<int> ord, low, parent;
    vector< vector< Edge<T> > > G;

    // ???????????± (first < second ??¨???????????????????´?)
    vector< pair<int, int> > bridges;
    int cnt, v;

    // init
    graphLink(vector< vector< Edge<T> > > S) {
        int n = S.size();
        ord.resize(n, -1), low.resize(n, 0),
        parent.resize(n, -1);
        cnt = 0, v = n;
        G = S;
    }

    // ?????§??????????????????
    bool is_bridge(int x, int y) {
        if(ord[x] > ord[y]) swap(x, y);
        return ord[x] < low[y];
    }

    // dfs ??¨???????????¨????????????
    // usage: dfs(root);
    void dfs(int cur, int prev=-1) {
        low[cur] = cnt;
        ord[cur] = cnt++;

        for(auto x : G[cur]) {
            if(x.to == prev) continue;
            if(ord[x.to] < 0) {
                parent[x.to] = cur;
                dfs(x.to, cur);

                low[cur] = min(low[cur], low[x.to]);
            }
            else {
                low[cur] = min(low[cur], ord[x.to]);
            }
            if(is_bridge(cur, x.to)) {
                int a = min(cur, x.to);
                int b = max(cur, x.to);
                bridges.emplace_back(make_pair(a, b));
            }
        }
    }

    // ??¢??????????±??????? (root ??? dfs ??¨??? root ??¨?????´?????????)
    // root ????????? 2 ????????£???????????°??¢???????????????
    // ????????\?????????????????¢????????? ord[parent] <= low[i] ?????¨?????¢???????????????
    // (lowlink ??§??????????????±????????????????????????????????????????????????)
    set<int> artPoints(int root) {
        set<int> se;
        int num = 0;
        rep(i,0,v) {
            if(parent[i] < 0) continue;
            if(parent[i] == root) num++;
            else if(ord[parent[i]] <= low[i]) se.insert(parent[i]);
        }
        if(num >= 2) se.insert(0);
        return se;
    }
};

signed main() {
    int V, E; cin >> V >> E;
    Graph<int> G(V);
    rep(i,0,E) {
        int s, t; cin >> s >> t;
        G[s].push_back(Edge<int>(t, 1));
        G[t].push_back(Edge<int>(s, 1));
    }
    graphLink<int> gr(G);
    gr.dfs(0);
    sort(gr.bridges.begin(), gr.bridges.end());
    for(auto x : gr.bridges) printf("%lld %lld\n", x.first, x.second);
}

Measured memory_bytes: 11888