#include <bits/stdc++.h>
using namespace std;

#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define MIN(a) *min_element(all(a))
#define MAX(a) *max_element(all(a))
#define SUM(a) accumulate(all(a), 0LL)
#define REP(i, n) for(int (i)=0; (i)<(n); (i)++)
#define RREP(i, n) for(int (i)=(n)-1; (i)>=0; (i)--)
#define FOR(i, m, n) for(int (i)=(m); (i)<(n); i++)
#define FORR(i, m, n) for(int (i)=(n)-1; (i)>=(m); i--)
#define debug(x) cerr << #x << " = " << x << endl
//#define int long long

typedef long long ll;
//ll const MOD = 998244353;
ll const MOD = 1e9+7;
int const inf = 1e9;
ll const INF = 1e18;

inline void ios_(){cin.tie(0); ios::sync_with_stdio(false);}
template<typename T> int size(const T& a){return (int)a.size();}
template<typename T> T Div(T a, T b){return (a + b - 1) / b;}
template<typename T> bool chmin(T& a, const T& b){if(a > b){a = b; return true;} return false;}
template<typename T> bool chmax(T& a, const T& b){if(a < b){a = b; return true;} return false;}

#include <vector>
#include <deque>
#include <queue>
#include <algorithm>
using ll = long long;

struct Graph {
    struct Edge {
        int from;
        int to;
        ll cost;
        Edge(int a, ll b) : to(a), cost(b) {}
        Edge(int a, int b, ll c) : from(a), to(b), cost(c) {}
    };

    int N;  //頂点数
    std::vector<std::vector<Edge>> edges;   //隣接リスト
    std::vector<ll> dist;   //ノードの深さ
    std::vector<int> deg;   //入次数
    vector<int> par;

    Graph(int n) : N(n), edges(n), dist(n, INF), deg(n, 0), par(n, -1) {}

    void connect(int a, int b, ll c) {   //辺を追加
        edges[a].emplace_back(Edge(a, b, c));
        deg[b]++;
    }

    bool visited(int v) {
        return dist[v] < INF;
    }

    void resetDist() {
        for(int i=0; i<N; i++) {
            dist[i] = INF;
        }
    }

    void dfs(int p, int v, ll d) {    //深さ優先探索
        if(visited(v)) return;

        dist[v] = d;

        for(const Edge& e : edges[v]) {
            if(e.to == p) continue;
            dfs(v, e.to, d + e.cost);
        }
    }

    void bfs(int v) {        //幅優先探索
        std::queue<Edge> que;
        for(const Edge& e : edges[v]) {
            que.push(e);
            dist[e.to] = e.cost;
        }

        dist[v] = 0;

        while(!que.empty()) {
            int u = que.front().to;
            ll d = que.front().cost;
            par[u] = que.front().from;
            que.pop();

            for(const Edge& e : edges[u]) {
                if(!visited(e.to)) {
                    que.push(Edge(e.from, e.to, d + e.cost));
                    dist[e.to] = d + e.cost;
                }
            }
        }
    }

    ll diameter() {  //木の直径を求める
        static ll res = INF;
        if(res != INF) return res;  //計算済みの場合

        dfs(-1, 0, 0);  //頂点0からの最遠頂点vを求める
        int v = std::max_element(dist.begin(), dist.end()) - dist.begin();

        resetDist();

        dfs(-1, v, 0);  //vからの最遠頂点を求める

        return res = *std::max_element(dist.begin(), dist.end());   //この2頂点間の距離が直径
    }

    void dijkstra(int start) {   //ダイクストラ法
        dist[start] = 0;

        auto fn = [](const Edge& a, const Edge& b){return a.cost > b.cost;};
        std::priority_queue<Edge, std::vector<Edge>, decltype(fn)> que(fn);

        for(const Edge& e : edges[start]) que.push(e);

        while(!que.empty()) {
            auto v = que.top().to;
            auto d = que.top().cost;
            que.pop();

            if(visited(v)) continue;
            else dist[v] = d;
            
            for(const Edge& e : edges[v]) {
                if(dist[e.to] == INF) {
                    que.push(Edge(e.from, e.to, e.cost + d));
                }
            }
        }
    }

    bool BellmanFord(int start) {    //ベルマンフォード法 (負の閉路がある場合はtrueを返す)
        dist[start] = 0;
        for(int i = 0; i < N; i++) {
            for(int j = 0; j < N; j++) {
                for(const Edge& e : edges[j]) {
                    if(visited(j) && dist[j] + e.cost < dist[e.to]) {
                        if(i == N-1) return true;  //N回目にも更新があるなら負の閉路が存在
                        dist[e.to] = dist[j] + e.cost;
                    }
                }
            }
        }
        return false;
    }

    std::vector<int> topologicalSort() { //トポロジカルソート
        std::queue<int> que;
        for(int i = 0; i < N; i++) {
            if(deg[i] == 0) que.push(i);
        }

        std::vector<int> result;

        while(!que.empty()) {
            auto v = que.front();
            que.pop();
            result.push_back(v);
            for(const Edge& e : edges[v]) {
                deg[e.to]--;
                if(deg[e.to] == 0) que.push(e.to);
            }
        }
        
        return result;
    }

    std::deque<int> findCycle() {
        std::vector<int> status(N, 0);
        std::deque<int> hist, result;

        for(int i = 0; i < N; i++) {
            int r = findCycleDfs(-1, i, hist);
            if(r == -1) continue;

            while(!hist.empty()) {
                int v = hist.back();
                result.push_front(v);
                hist.pop_back();
                if(v == r) break;
            }
            break;
        }

        return result;
    }

    int findCycleDfs(int p, int v, std::deque<int>& hist) {
        static std::vector<int> status(N, 0);
        status[v] = 1;
        hist.push_back(v);

        for(const Edge& e : edges[v]) {
            if(e.to == p || status[e.to] == 2) {
                continue;
            }
            if(status[e.to] == 1) {
                return e.to;
            }
            int r = findCycleDfs(v, e.to, hist);
            if(r != -1) return r;
        }

        hist.pop_back();
        status[v] = 2;
        return -1;
    }
};

signed main(){
    int n, m;
    cin >> n >> m;

    Graph G(n);
    REP(i, m){
        int a, b;
        cin >> a >> b;
        G.connect(a-1, b-1, 1);
        G.connect(b-1, a-1, 1);
    }

    G.bfs(0);

    cout << "Yes" << endl;
    FOR(i, 1, n){
        cout << G.par[i] + 1 << '\n';
    }

    return 0;
}


Measured memory_bytes: 18280