using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var nm = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
        var n = nm[0];
        var m = nm[1];

        var graph = new Dikstra(n);

        for (int i = 0; i < m; i++)
        {
            var tmp = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
            graph.Add(tmp[0] - 1, tmp[1] - 1);
            graph.Add(tmp[1] - 1, tmp[0] - 1);
        }

        var minDis = graph.GetMinCost(0);

        if(minDis.Any(t => t >= 1000000000000000))
        {
            Console.WriteLine("No");
            return;
        }

        Console.WriteLine("Yes");

        for (int i = 1; i < n; i++)
        {
            Console.WriteLine(graph.Route[i] + 1);
        }
    }
}

public class Dikstra
{
    public int N { get; }               // 頂点の数
    private List<Edge>[] _graph;        // グラフの辺のデータ

    public long[] Route { get; set; }

    /// <summary>
    /// 初期化
    /// </summary>
    /// <param name="n">頂点数</param>
    public Dikstra(int n)
    {
        N = n;
        Route = new long[n];
        _graph = new List<Edge>[n];        for (int i = 0; i < n; i++) _graph[i] = new List<Edge>();
    }

    /// <summary>
    /// 辺を追加
    /// </summary>
    /// <param name="a">接続元の頂点</param>
    /// <param name="b">接続先の頂点</param>
    /// <param name="cost">コスト</param>
    public void Add(int a, int b, long cost = 1)
            => _graph[a].Add(new Edge(b, cost));

    /// <summary>
    /// 最短経路のコストを取得
    /// </summary>
    /// <param name="start">開始頂点</param>
    public long[] GetMinCost(int start)
    {
        // コストをスタート頂点以外を無限大に
        var cost = new long[N];
        for (int i = 0; i < N; i++) cost[i] = 1000000000000000000;
        cost[start] = 0;

        // 未確定の頂点を格納する優先度付きキュー(コストが小さいほど優先度が高い)
        var q = new PriorityQueue<Vertex>(N * 10, Comparer<Vertex>.Create((a, b) => b.CompareTo(a)));
        q.Push(new Vertex(start, 0));

        while (q.Count > 0)
        {
            var v = q.Pop();

            // 記録されているコストと異なる(コストがより大きい)場合は無視
            if (v.cost != cost[v.index]) continue;

            // 今回確定した頂点からつながる頂点に対して更新を行う
            foreach (var e in _graph[v.index])
            {
                
                if (cost[e.to] > v.cost + e.cost)
                {
                    Route[e.to] = v.index;
                    // 既に記録されているコストより小さければコストを更新
                    cost[e.to] = v.cost + e.cost;
                    q.Push(new Vertex(e.to, cost[e.to]));
                }
            }
        }

        // 確定したコストを返す
        return cost;
    }

    public struct Edge
    {
        public int to;                      // 接続先の頂点
        public long cost;                   // 辺のコスト

        public Edge(int to, long cost)
        {
            this.to = to;
            this.cost = cost;
        }
    }

    public struct Vertex : IComparable<Vertex>
    {
        public int index;                   // 頂点の番号
        public long cost;                   // 記録したコスト

        public Vertex(int index, long cost)
        {
            this.index = index;
            this.cost = cost;
        }

        public int CompareTo(Vertex other)
            => cost.CompareTo(other.cost);
    }
}

class PriorityQueue<T> where T : IComparable<T>
{
    private readonly T[] _array;
    private readonly IComparer _comparer;
    public int Count { get; private set; } = 0;
    public T Root => _array[0];

    public PriorityQueue(int capacity, IComparer comparer = null)
    {
        _array = new T[capacity];
        _comparer = comparer;
    }

    /// <summary>
    /// 要素を挿入する
    /// </summary>
    public void Push(T item)
    {
        _array[this.Count] = item;
        Count += 1;

        var n = Count - 1;                  // 末尾(追加した)のノードの番号
        while (n != 0)
        {
            var parent = (n - 1) / 2;       // 親ノードの番号

            if (Compare(_array[n], _array[parent]) > 0)
            {
                Swap(n, parent);
                n = parent;
            }
            else
            {
                break;
            }
        }
    }

    /// <summary>
    /// 優先度の一番高いものを取り出す
    /// </summary>
    public T Pop()
    {
        Swap(0, this.Count - 1);            // 先頭要素を末尾にする
        Count -= 1;

        var parent = 0;                     // 親ノードの番号
        while (true)
        {
            var child = 2 * parent + 1;     // 子ノードの番号
            if (child > Count - 1) break;

            // 値の大きい方の子を選ぶ
            if (child < Count - 1 && Compare(_array[child], _array[child + 1]) < 0) child += 1;

            // 子の方が親より大きければ入れ替える
            if (Compare(_array[parent], _array[child]) < 0)
            {
                Swap(parent, child);
                parent = child;
            }
            else
            {
                break;
            }
        }

        return _array[Count];
    }

    /// <summary>
    /// 大きいものから列挙していく
    /// withPop = falseのときは順番関係なく取り出しもしないが素早く全要素を取得できる　
    /// </summary>
    public IEnumerable<T> GetAllElements(bool withPop = true)
    {
        int count = Count;
        for (int i = 0; i < count; i++)
        {
            if (withPop) yield return Pop();
            else yield return _array[count - i - 1];
        }
    }

    private int Compare(T a, T b)
    {
        if (_comparer == null) return a.CompareTo(b);
        return _comparer.Compare(a, b);
    }

    private void Swap(int a, int b)
    {
        var tmp = _array[a];
        _array[a] = _array[b];
        _array[b] = tmp;
    }
}

Measured memory_bytes: 63172