import java.util.*;
import java.io.*;
public class Main{
    static List<Integer> [] al;

    public static void main(String [] args) throws IOException{
        FastScanner sc=new FastScanner();
        int n=sc.nextInt();
        int m=sc.nextInt();
        al=new ArrayList[n];
        for(int i=0;i<n;i++)al[i]=new ArrayList<>();
        for(int i=0;i<m;i++){
            int u=sc.nextInt()-1;
            int v=sc.nextInt()-1;
            al[u].add(v);
            al[v].add(u);
        }

        Queue<Integer> q=new LinkedList<>();
        boolean [] vis=new boolean[n];
        int [] level=new int[n];
        q.add(0);
        vis[0]=true;
        while(!q.isEmpty()){
            int u=q.poll();
            for(int v : al[u]){
                if(!vis[v]){
                    vis[v]=true;
                    q.add(v);
                    level[v]=level[u]+1;
                }
            }
        }

        for(int i=0;i<n;i++){
            if(!vis[i]){
                System.out.println("No");
                return;
            }
        }
        System.out.println("Yes");
        StringBuilder sb=new StringBuilder("");
        for(int i=1;i<n;i++)sb.append(level[i]+"\n");
        System.out.println(sb.toString().trim());

    }

}

class FastScanner{
    private int BUFFER_SIZE = 1 << 16;

   private  DataInputStream din;

   private  byte[] buffer;

   private int bufferPointer, bytesRead;

   public FastScanner() {
       din = new DataInputStream(System.in);
       buffer = new byte[BUFFER_SIZE];
       bufferPointer = bytesRead = 0;
   }

   public FastScanner( String file_name) throws IOException {
       din = new DataInputStream(new FileInputStream(file_name));
       buffer = new byte[BUFFER_SIZE];
       bufferPointer = bytesRead = 0;
   }

   public String readLine() throws IOException {
        byte[] buf = new byte[64];
       int cnt = 0, c;
       while ((c = read()) != -1) {
           if (c == '\n')
               break;
           buf[cnt++] = (byte) c;
       }
       return new String(buf, 0, cnt);
   }

   public String next() throws IOException{

       byte c = read();
       while(Character.isWhitespace(c)){
           c = read();
       }

        StringBuilder builder = new StringBuilder();
       builder.append((char)c);
       c = read();
       while(!Character.isWhitespace(c)){
           builder.append((char)c);
           c = read();
       }

       return builder.toString();
   }

   public int nextInt() throws IOException {
       int ret = 0;
       byte c = read();
       while (c <= ' ')
           c = read();
        boolean neg = (c == '-');
       if (neg)
           c = read();
       do {
           ret = ret * 10 + c - '0';
       } while ((c = read()) >= '0' && c <= '9');

       if (neg)
           return -ret;
       return ret;
   }

   public int[] nextIntArray( int n) throws IOException {
        int arr[] = new int[n];
       for(int i = 0; i < n; i++){
           arr[i] = nextInt();
       }
       return arr;
   }

   public long nextLong() throws IOException {
       long ret = 0;
       byte c = read();
       while (c <= ' ')
           c = read();
        boolean neg = (c == '-');
       if (neg)
           c = read();
       do {
           ret = ret * 10 + c - '0';
       } while ((c = read()) >= '0' && c <= '9');
       if (neg)
           return -ret;
       return ret;
   }

   public long[] nextLongArray( int n) throws IOException {
        long arr[] = new long[n];
       for(int i = 0; i < n; i++){
           arr[i] = nextLong();
       }
       return arr;
   }

   public char nextChar() throws IOException{
       byte c = read();
       while(Character.isWhitespace(c)){
           c = read();
       }
       return (char) c;
   }

   public double nextDouble() throws IOException {
       double ret = 0, div = 1;
       byte c = read();
       while (c <= ' ')
           c = read();
        boolean neg = (c == '-');
       if (neg)
           c = read();

       do {
           ret = ret * 10 + c - '0';
       } while ((c = read()) >= '0' && c <= '9');

       if (c == '.') {
           while ((c = read()) >= '0' && c <= '9') {
               ret += (c - '0') / (div *= 10);
           }
       }

       if (neg)
           return -ret;
       return ret;
   }

   public double[] nextDoubleArray( int n) throws IOException {
        double arr[] = new double[n];
       for(int i = 0; i < n; i++){
           arr[i] = nextDouble();
       }
       return arr;
   }

   private void fillBuffer() throws IOException {
       bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
       if (bytesRead == -1)
           buffer[0] = -1;
   }

   private byte read() throws IOException {
       if (bufferPointer == bytesRead)
           fillBuffer();
       return buffer[bufferPointer++];
   }

   public void close() throws IOException {
       if (din == null)
           return;
       din.close();
   }

}


import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);

		int N = scan.nextInt();
		int M = scan.nextInt();
		int a,b;
		boolean[][] road = new boolean[N+1][N+1];
		for(int i = 0; i < M; i++) {
			a = scan.nextInt();
			b = scan.nextInt();
			if (a < b) {
				road[a][b] = true;
			} else {
				road[b][a] = true;
			}
		}

		Queue<Integer> order = new ArrayDeque<>();
		boolean[] visit = new boolean[N+1];
		order.add(1);
		visit[0] = true;
		visit[1] = true;
		int[] number = new int[N+1];
		int n;

		while (!order.isEmpty()) {
			n = order.poll();
			for (int i = 1; i < N+1; i++) {
				if (n < i) {
					if (road[n][i] && !visit[i]) {
						order.add(i);
						visit[i] = true;
						number[i] = n;
					}
				} else if (i < n){
					if (road[i][n] && !visit[i]) {
						order.add(i);
						visit[i] = true;
						number[i] = n;
					}
				}
			}
		}

		System.out.println("Yes");
		for (int i = 2; i < N+1; i++) {
			System.out.println(number[i]);
		}
	}
}


#pragma GCC optimize ("O3")
#pragma GCC target ("avx2")
//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

const int CM = 1 << 17, CL = 12;
char cn[CM + CL], * ci = cn + CM + CL, * owa = cn + CM, ct;
const ll ma0 = 1157442765409226768;
const ll ma1 = 1085102592571150095;
const ll ma2 = 71777214294589695;
const ll ma3 = 281470681808895;
const ll ma4 = 4294967295;
inline int getint() {
	if (ci - owa > 0) {
		memcpy(cn, owa, CL);
		ci -= CM;
		fread(cn + CL, 1, CM, stdin);
	}
	ll tmp = *(ll*)ci;
	int dig = 68 - __builtin_ctzll((tmp & ma0) ^ ma0);
	tmp = tmp << dig & ma1;
	tmp = tmp * 10 + (tmp >> 8) & ma2;
	tmp = tmp * 100 + (tmp >> 16) & ma3;
	tmp = tmp * 10000 + (tmp >> 32) & ma4;
	ci += 72 - dig >> 3;
	return tmp;
}
const int dm = 1 << 20;
char dn[dm], * di = dn;
inline void putint(int X) {
	int keta = 0;
	char C[10];
	while (X) {
		*(C + keta) = '0' + X % 10;
		X /= 10;
		keta++;
	}
	for (int i = keta - 1; i >= 0; i--)* di++ = (*(C + i));
	*di++ = '\n';
}

int to[400004], ne[400004], he[100001];
int kotae[100001], Q[100001];
int main() {
	//cin.tie(0);
	//ios::sync_with_stdio(false);

	int N = getint(), M = getint();
	int k = 1;
	rep(i, M) {
		int a = getint(), b = getint();
		to[k] = b;
		ne[k] = he[a];
		he[a] = k++;
		to[k] = a;
		ne[k] = he[b];
		he[b] = k++;
	}

	int q = 0;
	Q[q++] = 1;
	kotae[1] = 1;
	rep(i, N) {
		int u = Q[i];
		for (int v = he[u]; v; v = ne[v]) {
			int To = to[v];
			if (!kotae[To]) {
				kotae[To] = u;
				Q[q++] = To;
			}
		}
	}
	printf("Yes\n");

	for (int i = 2; i <= N; i++) putint(kotae[i]);
	fwrite(dn, 1, di - dn, stdout);

	Would you please return 0;
}


#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (n); i++)
using namespace std;
using ll = long long;
using P = pair<int, int>;

const inf INF = 1001001001;
vector<int> to[100005]

int main() {
    //スタートからの距離-1のノードへの指示ができればok
    //幅優先探索をすれば良い
    //各ノードにスタートからの距離とどこから来たか(たどるため)を記録する

    int n, m;
    cin >> n >> m;
    rep(i, m){
        int a, b;
        cin >> a >> b;
        --a; --b;
        //push_backは末尾に追加
        to[a].push_back(b);
        to[b].push_back(a);
    }

    queue<int> q;
    vector<int> dist(n, INF);
    vector<int> pre(n, -1);
    dist[0] = 0;
    q.push(0);
    while(!q.empty()){
        //queueの先頭を取り出し
        int v = q.front(); q.pop();
        //vとつながっているノードをなめていく
        for (int u: to[v]){
            if(dist[u] != INF) continue;
            dist[u] = dist[v] + 1;
            //親を記録
            pre[u] = v;
            //訪問済みにする
            q.push(u);
        }
    }

    //今回はどの部屋もつながっている条件があるので必ずYes
    cout << "Yes" << endl;
    rep(i, n){
        if(i == 0) continue;
        int ans = pre[i];
        ++ans;
        cout << ans << endl;
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
vector<int> visited;
vector<vector<int> > adj;
vector<int> parent;
vector<int> dp;
void dfs(int s,int p)
{
    visited[s]=1;
    for(auto it:adj[s])
    {
         if(dp[it]>dp[s]+1)
        {
            dp[it]=dp[s]+1;
            parent[it]=s;
        }
        if(!visited[it])
        dfs(it,s);

    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    adj.resize(n+1);
    visited.resize(n+1);
    parent.resize(n+1);
    dp.resize(n+1,1e7);
    for(int i=0;i<m;i++)
    {
        int x,y;
        cin>>x>>y;
        adj[x].push_back(y);
        adj[y].push_back(x);
    }
    dp[1]=0;
    dfs(1,-1);

    for(int i=2;i<=n;i++)
    {
        if(!visited[i])
        {
            cout<<"No"<<endl;
            return 0;
        }
    }
    cout<<"Yes"<<endl;
    for(int i=2;i<=n;i++)
    cout<<parent[i]<<endl;
}


#include<bits/stdc++.h>
using namespace std;
vector<int> visited;
vector<vector<int> > adj;
vector<int> parent;
void dfs(int s,int p)
{
    visited[s]=1;
    parent[s]=p;
    for(auto it:adj[s])
    {
        if(!visited[it])
        dfs(it,s);
    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    adj.resize(n+1);
    visited.resize(n+1);
    parent.resize(n+1);
    for(int i=0;i<m;i++)
    {
        int x,y;
        cin>>x>>y;
        adj[x].push_back(y);
        adj[y].push_back(x);
    }
    dfs(1,-1);
    for(int i=2;i<=n;i++)
    {
        if(!visited[i])
        {
            cout<<"No"<<endl;
            return 0;
        }
    }
    cout<<"Yes"<<endl;
    for(int i=2;i<=n;i++)
    cout<<parent[i]<<endl;
}


#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif

char rbuf[2800014];
char wbuf[699997];
int rbufl, wbufl;

#define getchar_unlocked() rbuf[rbufl++]
#define putchar_unlocked(c) wbuf[wbufl++]=(c)

inline uint32_t nextpint(void){ char c=getchar_unlocked(); uint32_t x=0; while('0'<=c){ x=x*10+c-'0'; c=getchar_unlocked(); } return x; }
inline void printpint(int32_t x){ if(x==0){putchar_unlocked('0');} int d=0; char s[10]; while(x){ s[d]='0'+x%10; x/=10; d++; } for (int i=d-1; i>=0; i--) putchar_unlocked(s[i]); putchar_unlocked('\n'); }

int edge[200000][2];

int qmem[400000];

int *e[100001];
int el[100001];

int prev[100001];

int s[100000];
int sl, sr;

int main(void){
	read(STDIN_FILENO, rbuf, sizeof(rbuf));
	int n=nextpint();
	int m=nextpint();
	for(int i=0; i<m; i++){
		int A=nextpint();
		int B=nextpint();
		edge[i][0]=A;
		edge[i][1]=B;
		el[A]++;
		el[B]++;
	}
	int ne=0;
	for(int i=1; i<=n; i++){
		e[i]=&qmem[ne];
		ne+=el[i];
		el[i]=0;
	}
	for(int i=0; i<m; i++){
		int A=edge[i][0];
		int B=edge[i][1];
		e[A][el[A]++]=B;
		e[B][el[B]++]=A;
	}
	int k=0;
	prev[1]=1;
	s[sr++]=1;
	while(sl<sr){
		k++;
		int from = s[sl++];
		for(int i=0; i<el[from]; i++){
			int to = e[from][i];
			if(prev[to]==0){
				prev[to]=from;
				s[sr++]=to;
			}
		}
	}
	if(k==n){
		putchar_unlocked('Y');
		putchar_unlocked('e');
		putchar_unlocked('s');
		putchar_unlocked('\n');
		for(int i=2; i<=n; i++){
			printpint(prev[i]);
		}
		write(STDOUT_FILENO, wbuf, wbufl);
	}else{
		puts("No");
	}
}


#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif

char rbuf[2800014];
char wbuf[699997];
int rbufl, wbufl;

#define getchar_unlocked() rbuf[rbufl++]
#define putchar_unlocked(c) wbuf[wbufl++]=(c)

uint32_t nextpint(void){ char c=getchar_unlocked(); uint32_t x=0; while('0'<=c){ x=x*10+c-'0'; c=getchar_unlocked(); } return x; }
void printpint(int32_t x){ if(x==0){putchar_unlocked('0');} int d=0; char s[10]; while(x){ s[d]='0'+x%10; x/=10; d++; } for (int i=d-1; i>=0; i--) putchar_unlocked(s[i]); putchar_unlocked('\n'); }

int edge[200000][2];

int qmem[400000];

int *e[100001];
int el[100001];

int prev[100001];

int s[100000];
int sl, sr;

int main(void){
	read(STDIN_FILENO, rbuf, sizeof(rbuf));
	int n=nextpint();
	int m=nextpint();
	for(int i=0; i<m; i++){
		int A=nextpint();
		int B=nextpint();
		edge[i][0]=A;
		edge[i][1]=B;
		el[A]++;
		el[B]++;
	}
	int ne=0;
	for(int i=1; i<=n; i++){
		e[i]=&qmem[ne];
		ne+=el[i];
		el[i]=0;
	}
	for(int i=0; i<m; i++){
		int A=edge[i][0];
		int B=edge[i][1];
		e[A][el[A]++]=B;
		e[B][el[B]++]=A;
	}
	int k=0;
	prev[1]=1;
	s[sr++]=1;
	while(sl<sr){
		k++;
		int from = s[sl++];
		for(int i=0; i<el[from]; i++){
			int to = e[from][i];
			if(prev[to]==0){
				prev[to]=from;
				s[sr++]=to;
			}
		}
	}
	if(k==n){
		putchar_unlocked('Y');
		putchar_unlocked('e');
		putchar_unlocked('s');
		putchar_unlocked('\n');
		for(int i=2; i<=n; i++){
			printpint(prev[i]);
		}
		write(STDOUT_FILENO, wbuf, wbufl);
	}else{
		puts("No");
	}
}


#include <stdio.h>
#include <stdlib.h>

#define ll long long
#define ARR_SIZE 210000
#define MOD ((ll)1e9 + 7)

typedef struct __node__ {
    int data;
    struct __node__ *next;
} Node;

int main(){
    int n, m, a[ARR_SIZE] = {}, b[ARR_SIZE] = {};
    scanf("%d %d", &n, &m);
    for(int i=0;i<m;i++) scanf("%d %d", a+i, b+i);
    // end input

    Node* room[ARR_SIZE];
    for(int i=1;i<=n;i++) room[i] = NULL;

    for(int path=0;path<m;path++){
        Node* p0 = calloc(1, sizeof(Node));
        p0->data = a[path];
        p0->next = room[b[path]];
        room[b[path]] = p0;

        Node* p1 = calloc(1, sizeof(Node));
        p1->data = b[path];
        p1->next = room[a[path]];
        room[a[path]] = p1;
    }

    int next_room[ARR_SIZE] = {};
    int child_room[ARR_SIZE] = {1};
    int child_room0[ARR_SIZE] = {};
    int num_children = 1;
    int num_children0 = 0;
    int flag = 1;

    if(room[1]==NULL){
        printf("No\n");
        return 0;
    }

    while(flag == 1){
        flag = 0;
        for(int i=0;i<num_children;i++){
            int parent_room = child_room[i];

            Node* ptr = room[parent_room];
            while(ptr!=NULL){
                int data = ptr->data;
                if(next_room[data]>0){
                    ptr = ptr->next;
                    continue;
                }
                next_room[data] = parent_room;
                child_room0[num_children] = data;
                num_children0 += 1;
                ptr = ptr->next;
                flag = 1;
            }
        }

        num_children = num_children0;
        for(int j=0;j<num_children;j++){
            child_room[j] = child_room0[j];
        }
        num_children0 = 0;
    }

    int count = 0;
    for(int r=2;r<=n;r++){
        if(next_room[r]>0){
            count += 1;
        }
    }

    if(count==n-1){
        printf("Yes\n");
        for(int r=2;r<=n;r++){
            printf("%d\n", next_room[r]);
        }
    }

    return 0;
}


#include <stdio.h>
#include <stdlib.h>

#define ll long long
#define ARR_SIZE 210000
#define MOD ((ll)1e9 + 7)

typedef struct __node__ {
    int data;
    struct __node__ *next;
} Node;

int main(){
    int n, m, a[ARR_SIZE] = {}, b[ARR_SIZE] = {};
    scanf("%d %d", &n, &m);
    for(int i=0;i<m;i++) scanf("%d %d", a+i, b+i);
    // end input

    Node* room[ARR_SIZE];
    for(int i=1;i<=n;i++) room[i] = NULL;

    for(int path=0;path<m;path++){
        Node* p0 = calloc(1, sizeof(Node));
        p0->data = a[path];
        p0->next = room[b[path]];
        room[b[path]] = p0;

        Node* p1 = calloc(1, sizeof(Node));
        p1->data = b[path];
        p1->next = room[a[path]];
        room[a[path]] = p1;
    }

    int next_room[ARR_SIZE] = {};
    int child_room[ARR_SIZE] = {1};
    int child_room0[ARR_SIZE];
    int num_children = 1;
    int num_children0 = 0;
    int flag = 1;

    if(room[1]==NULL){
        printf("No\n");
        return 0;
    }

    while(flag == 1){
        flag = 0;
        for(int i=0;i<num_children;i++){
            int parent_room = child_room[i];

            Node* ptr = room[parent_room];
            while(ptr!=NULL){
                int data = ptr->data;
                if(next_room[data]>0){
                    ptr = ptr->next;
                    continue;
                }
                next_room[data] = parent_room;
                child_room0[num_children] = data;
                num_children0 += 1;
                ptr = ptr->next;
                flag = 1;
            }
        }

        num_children = num_children0;
        for(int j=0;j<num_children;j++){
            child_room[j] = child_room0[j];
        }
        num_children0 = 0;
    }

    int count = 0;
    for(int r=2;r<=n;r++){
        if(next_room[r]>0){
            count += 1;
        }
    }

    if(count==n-1){
        printf("Yes\n");
        for(int r=2;r<=n;r++){
            printf("%d\n", next_room[r]);
        }
    }

    return 0;

    printf("---------------------------------\n");
    for(int r=1;r<=n;r++){
        Node *ptr = room[r];
        while(ptr!=NULL){
            printf("%d ", ptr->data);
            ptr = ptr->next;
        }
        printf("\n");
    }

    return 0;
}


#include <stdio.h>
#include <stdlib.h>

#define ll long long
#define ARR_SIZE 210000
#define MOD ((ll)1e9 + 7)

int main(){
    int n, m, a[ARR_SIZE] = {}, b[ARR_SIZE] = {};
    scanf("%d %d", &n, &m);
    for(int i=0;i<m;i++) scanf("%d %d", a+i, b+i);
    // end input

    int depth[ARR_SIZE] = {}, next[ARR_SIZE] = {};

    depth[1] = 1;
    next[1] = 1;
    for(int d=1;d<=n;d++){
        for(int r=1;r<=n;r++){
            if(depth[r]==d){
                //printf("room: %d, depth: %d\n", r, d);
                for(int i=0;i<m;i++){
                    if(b[i]==r){
                        //printf("00room: %d, path: %d %d\n", r, a[i], b[i]);
                        b[i] = a[i];
                        a[i] = r;
                    }

                    if(a[i]==r){
                        //printf("room: %d, path: %d %d\n", r, a[i], b[i]);
                        if(depth[b[i]]>0) continue;
                        depth[b[i]] = depth[r] + 1;
                        next[b[i]] = r;

                        a[i] = a[m-1];
                        b[i] = b[m-1];
                        m -= 1;
                    }
                }
            }
        }
        int count = 0;
        for(int r=1;r<=n;r++){
            if(next[r]>0){
                count++;
            }
        }
        if(count==n) break;
    }

    int count = 0;
    for(int r=1;r<=n;r++){
        if(next[r]>0){
            count++;
        }
    }

    if(count==n){
        printf("Yes\n");
        for(int r=2;r<=n;r++){
            printf("%d\n", next[r]);
        }
    }else{
        printf("No\n");
    }

    return 0;
}


function main(lines) {
  const [N, M] = splitN(lines[0]);

  const map = Array(N+1).fill(0).map(() => []);
  for (let i = 1; i <= M; i++) {
    const [a, b] = splitN(lines[i]);
    map[a].push(b);
    map[b].push(a);
  }
  const res = [null];
  for (let current = [1]; true; ) {
    const next = [];
    current.forEach(c => {
      map[c].forEach(n => {
        if (res[n-1] !== undefined) return;
        res[n-1] = c;
        next.push(n);
      });
    });
    if (!next.length) break;
    current = next;
  }

  if (res.filter(i => i !== undefined).length === N) {
    res[0] = 'Yes';
    console.log( res.join('\n') );
  } else {
    console.log('No');
  }
}

main( require("fs").readFileSync("/dev/stdin", "utf8").trim().split("\n") );

function splitN(s) {
  return s.split(' ').map(Number);
}


function main(lines) {
  const [N, M] = splitN(lines[0]);

  const map = Array(N+1).fill(0).map(() => []);
  for (let i = 1; i <= M; i++) {
    const [a, b] = splitN(lines[i]);
    map[a].push(b);
    map[b].push(a);
  }
  const res = [null];
  for (let current = [1]; true; ) {
    const next = [];
    current.forEach(c => {
      map[c].forEach(n => {
        if (res[n-1] !== undefined) return;
        res[n-1] = c;
        next.push(n);
      });
    });
    if (!next.length) break;
    current = next;
  }

  res[0] = 'Yes';
  console.log( res.join('\n') );
}

main( require("fs").readFileSync("/dev/stdin", "utf8").trim().split("\n") );

function splitN(s) {
  return s.split(' ').map(Number);
}


/*
-------関数一覧--------
arr1dto2d(Array) 一次元配列を二次元配列にします
pf(N)素因数分解した結果をオブジェクトで返します
gcd(a,b)最大公約数を返します
lcm(a,b)最小公倍数を返します
num(a,b)a-bを返します。ソート用です
isPrime(n)素数かどうか真偽値で返します
isNumber(n)数かどうか真偽値で返します
arrsum(arr)配列の合計値を返します
nibu(arr,n)n以下で最も大きい数の添字を返します(nを含みます)
br(input)入力を改行で区切ります
*/
const debugMode = false;
const inf = Number.MAX_SAFE_INTEGER;
const mod = 1000000007;
function Main(input){
  input = input.split("\n");
  input = arr1dto2d(input);
  var arr = new Array(input[0][0]+1);
  for(var i=0;i<arr.length;i++){
      arr[i] = [];
  }
 // console.log(arr)
  var ans = new Array(input[0][0]+1).fill(-1);
  ans[0] = 810;
  ans[1] = 810;
  input.shift();
  input.forEach(function(val){
    arr[val[0]].push(val[1]);
    arr[val[1]].push(val[0]);
  });
 // console.log(arr)
  var q = [];
  q.push(1)
  var nq = [];
  while(true){
    if(q.length == 0&&nq.length == 0){
      break;
    }else if(q.length == 0){
        q = q.concat(nq);
        nq.length = 0;
    }
  //  console.log(q)
    var mem = q.pop();
 /*   console.log("o:"+mem)
    console.log*/
    arr[mem].forEach(function(val){
      if(ans[val]==-1){
        ans[val] = mem;
        nq.push(val);
     //   console.log("q:"+val)
      }
    })
  }
  ans.shift();
  ans.shift();
  console.log("Yes");
  console.log(ans.join("\n"));
}Main(require("fs").readFileSync("/dev/stdin", "utf8").trim());
function zisyozyunn(a){
  var arr = [];
  for(var i=0;i<input[0];i++){
    arr.push(i+1);
  }
  var sum = 0;
  for(var i=0;i<a.length;i++){
    var f = arr.findIndex(val => val==a[i]);
    sum += factorialize(a.length-1-i)*f;
    arr.splice(f,1);
  }
  return sum;
}
function arrsum(arr){
  var sum = 0;
  for (var i=0,len=arr.length; i<len; ++i) {
      sum += arr[i]-0;
  };
  return sum;
}
function debug(val){
  if(debugMode==true){
    console.log(val)
  }
}
function arrMaxPoint(arr){
	var max = Number.MIN_SAFE_INTEGER;
	var point = -1;
	for(var i=0;i<arr.length;i++){
		if(max<arr[i]){
			max = arr[i];
			point = i;
		}
	}
	return point;
}
function arrMinPoint(arr){
	var min = Number.MAX_SAFE_INTEGER;
	var point = -1;
	for(var i=0;i<arr.length;i++){
		if(min>arr[i]){
			min = arr[i];
			point = i;
		}
	}
	return point;
}
function isPrime(n){
    if(false===Number.isInteger(n)){
        return false;
    }
    if(n<=1){
        return false;
    }
    if(2===n){
        return true;
    }
    if(0===n%2){
        return false;
    }
    var square_root = Math.floor(Math.sqrt(n));
    for(var i=3; i<=square_root; i+=2){
        if(0===n%i){
            return false;
        }
    }
    return true;
}
function isNumber(val){
	const pat = /^([1-9]\d*|0)$/;
	return pat.test(val);
}
function factorialize(num) {
  if (num === 0) { return 1; }
  return num * factorialize(num-1);
}
function arr1dto2d (arr){
	for(var i=0;i<arr.length;i++){
    arr[i]=arr[i].split(" ").map(Number);
    }
  return arr;
}
function rotate(array) {
  const ROW = array.length;
  const COL = array[0].length;
  const row = ROW-1;
  var a = new Array(COL);
  for (var c=0; c<COL; c++) {
    a[c] = new Array(ROW);
    for (var r=0; r<ROW; r++) {
      a[c][r] = array[row-r][c];
    }
  }
  return a;
}
function part_in(base,push,st){
	for(var i=st,p=0;p<push.length;i++,p++){
		base[i] = push[p];
	}
	return base;
}
function part_reverse(arr,s,g){
	var push = arr.slice(s-1,g);
  push.reverse();
	arr = part_in(arr,push,s-1);
	return arr;
}
function zeroPadding(num,length){
    return (num + '000000000000000000000000000000000').slice(0,length);
}
function arrsum(arr){
    var sum = 0;
    for (var i=0,len=arr.length; i<len; ++i) {
        sum += arr[i]-0;
    };
    return sum;
}
function pf(n) {
    var result = {};

    if (n === 1) {
        return {"1":1}
    }

    var init = 2;

    while (n !== 1) {
        var i = init;
        while (i < Number.MAX_SAFE_INTEGER) {
            if (n % i === 0) {
                n /= i;
                if (!(result[i] > 0)) {
                    result[i] = 0;
                }
                result[i]++;
                break;
            }
            i++;
        }
        init = i;
    }
    return result;
}
function gcd(a, b) {
    if (b === 0){
        return a
    }
    return gcd(b, a % b)
}
function lcm(a,b) {
    var g = (n, m) => m ? g(m, n % m) : n
    return a * b / g(a, b)
}
function num(a, b) {
  return a - b;
}
function nibu(a,searchValue){
	var index = -1;

//調べる左端を表す添字(index)
var left = 0;

//調べる右端を表す添字(index)
var right = a.length-1;

//左端と右端にデータがある間は処理を繰り返す
while(left <= right){

    //左右の真ん中を表す添字(index)
    middle =Math.floor((left +right)/2);

    //真ん中の値と探す値を比較する
    if(a[middle]==searchValue){
        //一致した場合、変数に入れて処理終了
        index = middle;
        break;
    }else if(a[middle]<searchValue){
        //探す値より小さい場合、左側にはもっと小さい値しかないので左端の値を真ん中の値の右に移動する
        left = middle +1;
    }else{
        //探す値より大きい場合、右側にはもっと大きい値しかないので右端の値を真ん中の値の左に移動する
        right = middle -1;
    }
}
if(index!=-1) return index;
else return left;
}
function br(input){
  return input.split("\n");
}
function is_sortred(arr){
  var flag = true;
  for(var i=1;i<arr.length;i++){
    if(arr[i-1]>arr[i]){
      flag = false;
      break;
    }
  }
  return flag;
}
function primeFactorization(n) {

	// 平方根を保存
	var s = Math.floor(Math.sqrt(n));

	var r = 0;

	var result = {};

	// 2から平方根までの素因数を求める
	for (var i = 2;i <= s;i++) {

		if ((n % i) == 0) {

			r = 0; // 指数カウンタクリア

			do {

				r++; // 指数カウンタプラス

				n = n / i;

			} while ((n % i) == 0);

			// 素因数iを指数とともに保存
			result[i]=r;

		}

	}

	// 残った素数を追加
	if (n > s) {
		result[n] = 1;
	}

	return result;

}


const main = (input) => {
  const [a, ...qs] = input.trim().split('\n')
  const [N,] = a.split(' ').map(Number)
  const q = qs.map(v => v.split(' '))

  const cave = new Array(N+1).fill().map(() => [])

  for (let [a, b] of q) {
    cave[a].push(b)
    cave[b].push(a)
  }

  const visited = { '1': true }
  const ans = ['Yes', ...new Array(N).fill(0)]
  let queue = [1]

  while (queue.length) {
    const nextQ = []
    while (queue.length) {
      const v = queue.shift()
      const links = cave[v]

      for (let l of links) {
        if (visited[l]) continue
        nextQ.push(l)
        ans[l] = v
        visited[l] = true
      }
    }

    queue = nextQ
  }

  for (let i=0; i<=N; i++) {
    if (i===1) continue
    console.log(ans[i])
  }
  return null
}

process.env.MYTEST ? test() : main(require('fs').readFileSync('/dev/stdin', 'utf8'))


const main = (input) => {
  const [a, ...qs] = input.trim().split('\n')
  const [N, M] = a.split(' ').map(Number)
  const q = qs.map(v => v.split(' '))

  const cave = new Array(N+1).fill([])

  for (let [a, b] of q) {
    cave[a] = [...cave[a], b]
    cave[b] = [...cave[b], a]
  }

  const visited = { '1': true }
  const ans = ['Yes', ...new Array(N).fill(0)]
  let queue = [1]

  while (queue.length) {
    const nextQ = []
    while (queue.length) {
      const v = queue.shift()
      const links = cave[v]

      for (let l of links) {
        if (visited[l]) continue
        nextQ.push(l)
        ans[l] = v
        visited[l] = true
      }
    }

    queue = nextQ
  }

  for (let i=0; i<=N; i++) {
    if (i===1) continue
    console.log(ans[i])
  }
  return null
}

process.env.MYTEST ? test() : main(require('fs').readFileSync('/dev/stdin', 'utf8'))


let input = require("fs").readFileSync("/dev/stdin", "utf8")

function main({ input, load, yesno, math_sum, log_json }) {
    const [N,M] = load(2)
    const [A,B] = load(M,2)

    const rooms = new Array(N+1).fill(0)    // [room] = sign
    rooms[0] = -1
    rooms[1] = -1

    const rest = [1]
    while(rest.length) {
        inifinite_loop_preventer()

        const room = rest.shift()
        for(let i = 0; i < M; i++) {
            let from = null, to = null

            if(A[i] === room) [from, to] = [B[i], A[i]]
            if(B[i] === room) [from, to] = [A[i], B[i]]
            if(from === null) continue

            if(!rooms[from]) {
                rooms[from] = to
                rest.push(from)
            }
        }
    }

    if(rooms.includes(0)) return 'No'

    console.log('Yes')
    return rooms.slice(2).join('\n')
}

// console.time()
let inputs = input.split(/[\s\n]/)
let inifinite_loop_prevent_counter = 0
let result = main({
    input,
    yesno: value => value ? 'Yes' : 'No',
    math_sum: numbers => numbers.reduce((acc, cur) => acc + cur, 0),
    load(rows = 1, cols = 1, type = Number) {
        const length = rows * cols
        let result = inputs.splice(0, length)
        if(type !== String) result = result.map(type)
        if(cols > 1) {
            const arrays = new Array(cols)
            for(let col = 0; col < cols; col++) {
                arrays[col] = new Array()
                for(let row = 0; row < rows; row++) {
                    arrays[col].push(result[row * cols + col])
                }
            }
            result = arrays
        }
        return result
    },
    log_json(value) {
        console.log(JSON.stringify(value))
    },
})

if(result === undefined) {
    console.warn("result is undefined")
} else {
    console.log(result)
}
// console.timeEnd()

function inifinite_loop_preventer(max = 1e5) {
    inifinite_loop_prevent_counter++
    if(inifinite_loop_prevent_counter >= max) {
        throw new Error("Infinite loop")
    }
}

function math_max(numbers, initial_value = null) {
    let result = (initial_value === null) ? numbers[0] : initial_value
    for(const n of numbers) if(n > result) result = n
    return result
}

function math_min(numbers, initial_value = null) {
    let result = (initial_value === null) ? numbers[0] : initial_value
    for(const n of numbers) if(n < result) result = n
    return result
}

// 素因数分解 { 素数: n乗 }
function math_prime_factors(n) {
    const result = {}

    for(let i = 2; i * i <= n; i++) {
        if(n % i === 0) {
            n /= i
            result[i] = 1

            while(n % i === 0) {
                n /= i
                result[i]++
            }
        }
    }

    if(n > 1) result[n] = 1

    return result
}


package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	out := bufio.NewWriter(_w)
	defer out.Flush()
	buf := make([]byte, 4096)
	_i := len(buf)
	rc := func() byte {
		if _i == len(buf) {
			_r.Read(buf)
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}
	type pair struct{ v, fa int }

	n, m := r(), r()
	g := make([][]int, n+1)
	for ; m > 0; m-- {
		v, w := r(), r()
		g[v] = append(g[v], w)
		g[w] = append(g[w], v)
	}

	ans := make([]int, n+1)
	vis := make([]bool, n+1)
	q := []pair{{1, 0}}
	vis[1] = true
	cnt := 1
	for len(q) > 0 {
		p := q[0]
		q = q[1:]
		v := p.v
		for _, w := range g[v] {
			if w != p.fa && !vis[w] {
				vis[w] = true
				cnt++
				ans[w] = v
				q = append(q, pair{w, v})
			}
		}
	}
	if cnt < n {
		Fprint(out, "No")
		return
	}
	Fprintln(out, "Yes")
	for _, v := range ans[2:] {
		Fprintln(out, v)
	}
}

func main() { run(os.Stdin, os.Stdout) }


package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

var DEBUG = true

func main() {
	defer Flush()
	N := readi()
	M := readi()

	G := make([][]int, N)
	for i := 0; i < M; i++ {
		a := readi() - 1
		b := readi() - 1
		G[a] = append(G[a], b)
		G[b] = append(G[b], a)
	}

	q := make([]int, 0, N)

	push := func(x int) {
		q = append(q, x)
	}
	pop := func() int {
		res := q[0]
		q = q[1:]
		return res
	}

	dist := make([]int, N)
	for i := range dist {
		dist[i] = math.MaxInt64
	}

	prev := make([]int, N)
	for i := range prev {
		prev[i] = -1
	}

	push(0)
	dist[0] = 0
	prev[0] = 0

	for 0 < len(q) {
		v := pop()
		//dbg(v, dist, prev)
		for _, u := range G[v] {
			nd := dist[v] + 1
			if dist[u] <= nd {
				continue
			}
			dist[u] = nd
			prev[u] = v
			push(u)
		}
		//dbg("q", q)
	}

	for _, t := range prev {
		if t == -1 {
			println("No")
			return
		}
	}
	println("Yes")
	for i := 1; i < N; i++ {
		println(prev[i] + 1)
	}

}

// -----------------------------------------------------------------------------

// IO helper functions

// Returns next token from input.  It must be initialized by SetInput()
// before the first call.
var nextToken func() ([]byte, error)
var nextLine func() ([]byte, error)

// Holds a buffer for output.  It must be initialized by SetOutput().
// All IO fucntions (read*() and [e]print*()) should write to OutputWriter
// instead of this.
var OutputBuffer *bufio.Writer

// Holds an io.Writer.  It must be initialized by SetOutput()
var OutputWriter io.Writer

// Set IO functions for interactive input/output.
func SetInteractive(w io.Writer, r io.Reader) {
	SetUnbefferedInput(r)
	OutputBuffer = nil
	OutputWriter = w
}

// Setup OutputBuffer and OutputWriter.
func SetOutput(w io.Writer) {
	OutputBuffer = bufio.NewWriter(w)
	OutputWriter = OutputBuffer
}

// Flushes OutputBuffer
func Flush() {
	if OutputBuffer != nil {
		OutputBuffer.Flush()
	}
}

// Returns true if c is a white space
func IsSpace(c byte) bool {
	switch c {
	case '\t', '\n', '\v', '\f', '\r', ' ':
		return true
	}
	return false
}

func IsNewLine(c byte) bool {
	switch c {
	case '\n', '\r':
		return true
	}
	return false
}

// Setup nextToken with input buffer.
func SetInput(r io.Reader) {
	buf := new(bytes.Buffer)
	var b []byte

	var i int
	rest := func() ([]byte, error) {
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		return b[j:i], nil
	}
	initial := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextToken = rest
		return rest()
	}
	nextToken = initial

	restLn := func() ([]byte, error) {
		for i < len(b) && IsNewLine(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsNewLine(b[i]) {
			i++
		}
		return b[j:i], nil
	}

	initialLn := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextLine = restLn
		return restLn()
	}
	nextLine = initialLn
}

// Setup nextToken without input buffer.
func SetUnbefferedInput(r io.Reader) {
	buf := bufio.NewReader(r)
	var b []byte

	var i int
	nextToken = func() ([]byte, error) {
		var err error
		if i == len(b) {
			b, err = buf.ReadBytes('\n')
			if err != nil {
				return nil, err
			}
			i = 0
			j := len(b) - 1
			for 0 <= j && IsSpace(b[j]) {
				j--
			}
			b = b[0 : j+1]
		}
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		if i == j {
			return nil, io.ErrUnexpectedEOF
		}
		return b[j:i], nil
	}
}

// -----------------------------------------------------------------------------

// IO functions

// Reads next token and return it as []byte
func readb() []byte {
	b, err := nextToken()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Reads next token and return it as string
func reads() string {
	return string(readb())
}

// Read next line as []byte.  Trailing '\n' will not be included.
// See also comments on readb()
func readbln() []byte {
	b, err := nextLine()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Read next line as string
func readsln() string {
	return string(readbln())
}

// Reads next token and return it as int64
func readll() int64 {
	i, err := strconv.ParseInt(reads(), 10, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// Reads next token and return it as int
func readi() int {
	return int(readll())
}

// Reads next token and return it as float64
func readf() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// Write args to OutputWriter with the format f
func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(OutputWriter, f, args...)
}

// Write args to OutputWriter without format
func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(OutputWriter, args...)
}

// Write args to stderr with the format f
func eprintf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, f, args...)
}

// Write args to stderr without format
func eprintln(args ...interface{}) (int, error) {
	return fmt.Fprintln(os.Stderr, args...)
}

func dbgf(f string, args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintf(os.Stderr, f, args...)
}

func dbg(args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintln(os.Stderr, args...)
}

// -----------------------------------------------------------------------------

// Utilities

func sumSlice(a []int) int {
	var res int
	for _, v := range a {
		res += v
	}
	return res
}

func sumSlicell(a []int64) int64 {
	var res int64
	for _, v := range a {
		res += v
	}
	return res
}

func readInts(N int) (int, []int) {
	if N == 0 {
		N = readi()
	}
	a := make([]int, N)
	for i := range a {
		a[i] = readi()
	}
	return N, a
}

func readIntsll(N int) (int, []int64) {
	if N == 0 {
		N = readi()
	}
	a := make([]int64, N)
	for i := range a {
		a[i] = readll()
	}
	return N, a
}

// -----------------------------------------------------------------------------

// Simple math functions

const (
	// big prime
	INF  = 1000000007
	INF2 = 1000000009
	INF3 = 998244353
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func minll(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func minf(a, b float64) float64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxll(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func maxf(a, b float64) float64 {
	if a < b {
		return b
	}
	return a
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func absll(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

func absf(a float64) float64 {
	if a < 0 {
		return -a
	}
	return a
}

// egcd(a, b) returns d, x, y:
//   d is gcd(a,b)
//   x, y are  integers that satisfy ax + by = d
func egcd(a, b int) (int, int, int) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcd(b, a%b)
	return d, y, x - a/b*y
}

func egcdll(a, b int64) (int64, int64, int64) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcdll(b, a%b)
	return d, y, x - a/b*y
}

func gcd(a, b int) int {
	d, _, _ := egcd(a, b)
	return d
}

func gcdll(a, b int64) int64 {
	d, _, _ := egcdll(a, b)
	return d
}

// set up IO functions
func init() {
	// for non-interactive
	SetInput(os.Stdin)
	SetOutput(os.Stdout)

	// Enable below when interactive.  Its ok to leave above intact.
	// SetInteractive(os.Stdout, os.Stdin)
}


// 1からスタンプを押していくBFS
// golangでpriority queueもってないから愚直FIFOで間に合うかどうかは正直わからん
// ちょっとだけIOを高速化したバージョン
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

type Pos struct {
	cur, pre int
}

var sc = bufio.NewScanner(os.Stdin)
var out = bufio.NewWriter(os.Stdout)

func main() {
	buf := make([]byte, 1024*1024)
	sc.Buffer(buf, bufio.MaxScanTokenSize)
	sc.Split(bufio.ScanWords)
	defer out.Flush()
	N, M := nextInt(), nextInt()

	T := make([][]int, N+1)
	for i := 1; i <= N; i++ {
		T[i] = []int{}
	}
	for i := 0; i < M; i++ {
		A, B := nextInt(), nextInt()
		T[A] = append(T[A], B)
		T[B] = append(T[B], A)
	}
	passed := make([]int, N+1)
	passed[1] = -1
	queue := []Pos{Pos{cur: 1, pre: 0}}
	for len(queue) > 0 {
		nex_queue := []Pos{}
		for i := 0; i < len(queue); i++ {
			now := queue[i]
			for _, nex := range T[now.cur] {
				if passed[nex] == 0 {
					nexPos := Pos{cur: nex, pre: now.cur}
					passed[nex] = now.cur
					nex_queue = append(nex_queue, nexPos)
				}
			}
		}
		queue = nex_queue
	}
	fmt.Fprintln(out, "Yes")
	for _, ans := range passed[2:] {
		fmt.Fprintln(out, ans)
	}

}

func next() string {
	sc.Scan()
	return sc.Text()
}

func nextInt() int {
	a, _ := strconv.Atoi(next())
	return a
}


package main
import (
    "fmt"
)
func main(){
    var n, m int
    fmt.Scan(&n)
    fmt.Scan(&m)

    // cango := make(map[int][]int)
    cango := make([][]int, 100010)

    for i := 0; i < m; i++ {
        var a, b int
        fmt.Scan(&a)
        fmt.Scan(&b)

        cango[a] = append(cango[a], b)
        cango[b] = append(cango[b], a)
    }

    var q Queue
    q.Add(1)

    // togo := make(map[int]int)
    togo := make([]int, 100010)

    for len(q) > 0 {
        now := q.Remove()
        for i := 0; i < len(cango[now]); i++ {
            if togo[cango[now][i]] == 0 {
                togo[cango[now][i]] = now
                q.Add(cango[now][i])
            }
        }
    }

    var ans []int
    for i := 2; i <= n; i++ {
        if x := togo[i]; x != 0 {
            ans = append(ans, x)
        } else {
            fmt.Println("No")
            return
        }
    }

    fmt.Println("Yes")
    for i := 0; i < len(ans); i++ {
        fmt.Println(ans[i])
    }
}

type Queue []int

func (q *Queue) Add (n int) {
    *q = append(*q, n)
}

func (q *Queue) Remove () int {
    temp := *q
    *q = temp[1:]
    return temp[0]
}


package main
import (
    "fmt"
)
func main(){
    var n, m int
    fmt.Scan(&n)
    fmt.Scan(&m)

    cango := make(map[int][]int)
    for i := 0; i < m; i++ {
        var a, b int
        fmt.Scan(&a)
        fmt.Scan(&b)

        cango[a] = append(cango[a], b)
        cango[b] = append(cango[b], a)
    }

    var q Queue
    q.Add(1)

    togo := make(map[int]int)

    for len(q) > 0 {
        now := q.Remove()
        for i := 0; i < len(cango[now]); i++ {
            if _, ok := togo[cango[now][i]]; !ok  {
                togo[cango[now][i]] = now
                q.Add(cango[now][i])
            }
        }
    }

    fmt.Println("Yes")
    for i := 2; i <= n; i++ {
        if v, ok := togo[i]; ok {
            fmt.Println(v)
        }
    }

}

type Queue []int

func (q *Queue) Add (n int) {
    *q = append(*q, n)
}

func (q *Queue) Remove () int {
    temp := *q
    *q = temp[1:]
    return temp[0]
}


package main
import (
    "fmt"
)
func main(){
    var n, m int
    fmt.Scan(&n)
    fmt.Scan(&m)

    cango := make(map[int][]int)
    for i := 0; i < m; i++ {
        var a, b int
        fmt.Scan(&a)
        fmt.Scan(&b)

        cango[a] = append(cango[a], b)
        cango[b] = append(cango[b], a)
    }

    var q Queue
    q.Add(1)

    togo := make(map[int]int)

    for len(q) > 0 {
        now := q.Remove()
        for i := 0; i < len(cango[now]); i++ {
            if _, ok := togo[cango[now][i]]; !ok &&  {
                togo[cango[now][i]] = now
                q.Add(cango[now][i])
            }
        }
    }

    fmt.Println("Yes")
    for i := 2; i <= n; i++ {
        if v, ok := togo[i]; ok {
            fmt.Println(v)
        }
    }
}

type Queue []int

func (q *Queue) Add (n int) {
    *q = append(*q, n)
}

func (q *Queue) Remove () int {
    temp := *q
    *q = temp[1:]
    return temp[0]
}


n,m=gets.split.map(&:to_i)
to=Array.new(n+1){[]}
m.times do
  a,b=gets.split.map(&:to_i)
  to[a] << b
  to[b] << a
end
dist=0
d=[nil,0]
ans=[nil,1]
stock=[]
to[1].each do |j|
  stock << j
  ans[j]=1
end

while !stock.empty?
  s=stock.shift
  to[s].each do |t|
    unless ans[t]
      stock << t
      ans[t] = s
    end
  end
end

if ans[2..n+1].any? nil
  puts 'No'
else
  puts 'Yes'
  puts  ans[2..n+1]
end


n, m = gets.split.map(&:to_i)
graph = Array.new(n + 1) { [] }

m.times do
  a, b = gets.split.map(&:to_i)
  graph[a] << b
  graph[b] << a
end

dist = []
dist[1] = 0
queue = [1]
ret = []

while queue.any?
  v = queue.shift

  graph[v].each do |i|
    next if dist[i]

    dist[i] = dist[v] + 1
    queue << i
    ret[i] = v
  end
end

puts :Yes
puts ret.compact


END { load __FILE__ unless $stdin.eof? }

n, m = gets.split.map!(&:to_i)

nbrs = Array.new(n + 1) { [] }
m.times do
  a, b = gets.split.map!(&:to_i)
  nbrs[a] << b
  nbrs[b] << a
end

q = [1]
dir = Array.new(n + 1)
dir[0] = dir[1] = 0
while (x = q.shift)
  nbrs[x].each do |y|
    next if dir[y]
    dir[y] = x
    q << y
  end
end

if dir.all?
  puts :Yes, dir.drop(2)
else
  puts :No
end


n,m=gets.split.map(&:to_i)
to=Array.new(n+1){[]}
m.times do
  a,b=gets.split.map(&:to_i)
  to[a] << b
  to[b] << a
end
dist=0
d=[nil,0]
ans=[nil,1]
stock=[]
to[1].each do |j|
  stock << j
  ans[j]=1
end

while !stock.empty?
  s=stock.shift
  to[s].each do |t|
    unless ans[t]
      stock << t
      ans[t] = s
    end
  end
end
puts  ans[2..n+1]


n,m = gets.chomp.split(' ').map(&:to_i)
visited = Array.new(n,false)
ans = Array.new(n){0}
path = Array.new(n){Array.new(n){0}}
m.times do
    x,y = gets.chomp.split(' ').map(&:to_i)
    path[x-1][y-1] = 1
    path[y-1][x-1] = 1
end

s = [[0,0]]
while s.size > 0
    now = s.shift
    if visited[now[0]]
        next
    end
    visited[now[0]] = true
    ans[now[0]] = now[1]
    path[now[0]].size.times do |i|
        if path[now[0]][i] == 1
            s << [i,now[0]]
        end
    end
end

puts "Yes"
ans[1..-1].each do |a|
    puts a+1
end


def get_int_array
    gets.strip.split(' ').map(&:to_i)
end

n, m = get_int_array

ps = n.times.map{|i| Array.new(0) }

m.times.each{|i|
    p, q = get_int_array
    ps[p-1].push q-1
    ps[q-1].push p-1
}

ptos = n.times.map{|i| nil }

queue = []

ps[0].each{|i| queue.push [i, 0] }

while queue.any?
    pnext, pfrom = queue.shift
    if ptos[pnext].nil?
        ptos[pnext] = pfrom + 1 if ptos[pnext].nil?
        (ps[pnext] & pf).each{|i| queue.push [i, pnext] }
    end
end

ptos = ptos.drop(1)
# p pf
if ptos.any?{|i| i.nil? }
    puts 'No'
else
    puts 'Yes'
    puts ptos
end


use proconio::*;

#[fastout]
fn run() {
    input! {
        n: usize,
        m: usize,
        mut e: [(usize, usize); m],
    }
    let mut cnt = vec![0; n];
    for e in e.iter_mut() {
        e.0 -= 1;
        e.1 -= 1;
        cnt[e.0] += 1;
        cnt[e.1] += 1;
    }
    let mut buf = vec![0usize; 2 * m];
    let mut buf = buf.as_mut_slice();
    let mut g = Vec::with_capacity(n);
    for c in cnt.iter() {
        let (x, y) = buf.split_at_mut(*c);
        g.push(x);
        buf = y;
    }
    for (a, b) in e {
        cnt[a] -= 1;
        g[a][cnt[a]] = b;
        cnt[b] -= 1;
        g[b][cnt[b]] = a;
    }
    let mut prev = vec![n; n];
    prev[0] = 0;
    let mut q = std::collections::VecDeque::new();
    q.push_back(0);
    while let Some(v) = q.pop_front() {
        for &u in g[v].iter() {
            if prev[u] == n {
                prev[u] = v;
                q.push_back(u);
            }
        }
    }
    println!("Yes");
    for p in prev.iter().skip(1) {
        println!("{}", *p + 1);
    }
}

fn main() {
    run();
}


use proconio::*;

#[fastout]
fn run() {
    input! {
        n: usize,
        m: usize,
        mut e: [(usize, usize); m],
    }
    let mut cnt = vec![0; n];
    for e in e.iter_mut() {
        e.0 -= 1;
        e.1 -= 1;
        cnt[e.0] += 1;
        cnt[e.1] += 1;
    }
    let mut buf = vec![0usize; 2 * m];
    let mut buf = buf.as_mut_slice();
    let mut g = Vec::with_capacity(n);
    for c in cnt.iter() {
        let (x, y) = buf.split_at_mut(*c);
        g.push(x);
        buf = y;
    }
    for (a, b) in e {
        cnt[a] -= 1;
        g[a][cnt[a]] = b;
        cnt[b] -= 1;
        g[b][cnt[b]] = a;
    }
    let mut prev = vec![n; n];
    prev[0] = 0;
    let mut q = std::collections::VecDeque::with_capacity(n);
    q.push_back(0);
    while let Some(v) = q.pop_front() {
        for &u in g[v].iter() {
            if prev[u] == n {
                prev[u] = v;
                q.push_back(u);
            }
        }
    }
    println!("Yes");
    for p in prev.iter().skip(1) {
        println!("{}", *p + 1);
    }
}

fn main() {
    run();
}


use proconio::*;

#[fastout]
fn run() {
    input! {
        n: usize,
        m: usize,
        mut e: [(usize, usize); m],
    }
    let mut cnt = vec![0; n];
    for e in e.iter_mut() {
        e.0 -= 1;
        e.1 -= 1;
        cnt[e.0] += 1;
        cnt[e.1] += 1;
    }
    let mut g: Vec<_> = cnt.into_iter().map(|c| Vec::with_capacity(c)).collect();
    for (a, b) in e {
        g[a].push(b);
        g[b].push(a);
    }
    let mut prev = vec![n; n];
    prev[0] = 0;
    let mut q = std::collections::VecDeque::new();
    q.push_back(0);
    while let Some(v) = q.pop_front() {
        for &u in g[v].iter() {
            if prev[u] == n {
                prev[u] = v;
                q.push_back(u);
            }
        }
    }
    println!("Yes");
    for p in prev.iter().skip(1) {
        println!("{}", *p + 1);
    }
}

fn main() {
    run();
}


use std::*;
use std::io::*;
use std::iter::Iterator;
use std::str::FromStr;
#[allow(unused_imports)]
use std::fmt::{Display, Formatter};

#[allow(dead_code)]
fn main() {
  let stdin = stdin();
  let r = &mut BufReader::new(stdin.lock());
  let stdout = stdout();
  let w = &mut BufWriter::new(stdout.lock());
  let stderr = stderr();
  let err = &mut BufWriter::new(stderr.lock());
  run(r, w, err);
  w.flush().unwrap();
  err.flush().unwrap();
}

macro_rules! _ft { () => (impl FnOnce(&mut Cursor<Vec<u8>>, &mut Vec<u8>, &mut Vec<u8>)); }

#[allow(dead_code)]
fn test(input: &str, output: &str, f: _ft!()) {
  let r = &mut Cursor::new(input.as_bytes().to_vec());
  let w: &mut Vec<u8> = &mut Vec::new();
  let err: &mut Vec<u8> = &mut Vec::new();
  f(r, w, err);
  let mut stderr = stderr();
  writeln!(stderr, "{}", String::from_utf8(err.to_vec()).unwrap()).unwrap();
  stderr.flush().ok();
  assert_eq!(String::from_utf8(w.to_vec()).unwrap().trim(), output.trim())
}

#[allow(unused_macros)]
macro_rules! t {
  ($f: ident => $input: expr, $output: expr) => (
    #[test]
    fn $f() { test($input, $output, run); }
  );
}

macro_rules! _display_st {
    ($f: expr; $name: expr, ) => (write!($f, "{}", $name)?);
    ($f: expr; $name: expr) => (_display_st!($f; $name, ));
    ($f: expr; $name: expr, $($rest: expr),+, ) => (
      _display_st!($f; $name);
      write!($f, " ")?;
      _display_st!($f; $($rest, )+);
    );
    ($f: expr; $name: expr, $($rest: expr),+) => (_display_st!($f; $name, $($rest, )+));
}

macro_rules! _st_iter_parse {
  ($iter: expr; $($p: ident : $t: ty),+; ) => (Self {
    $($p: $iter.next().unwrap().parse::<$t>().unwrap(), )+
  });
  ($iter: expr; $($p: ident : $t: ty),+; 1~) => (Self {
    $($p: $iter.next().unwrap().parse::<$t>().unwrap() - 1, )+
  });
}

/// 構造体を作成する
#[allow(unused_macros)]
macro_rules! st {
  ($name: ident => $($p: ident : $t: ty),+; $($rest: tt)*) => (
    struct $name { $($p : $t),+ }
    impl FromStr for $name {
      type Err = ();
      fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        let mut iter = s.split_whitespace();
        Ok(_st_iter_parse!(iter; $($p : $t),+; $($rest)*))
      }
    }
    impl Display for $name {
      fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        _display_st!(f; $(&self.$p, )+);
        Ok(())
      }
    }
  );
  ($name: ident => $($p: ident : $t: ty),+) => (st!($name => $($p : $t),+; ););

  ($name: ident => $($($p: ident),+: $t: ty);+) => (st!($name => $($($p : $t),+),+););
  ($name: ident => $($($p: ident),+: $($t: ty),+);+) => (st!($name => $($($p : $t),+),+););
  ($name: ident => $($p: ident),+: $t: ty) => (st!($name => $($p : $t),+););
  ($name: ident => $($p: ident),+: $($t: ty),+) => (st!($name => $($p : $t),+););

  ($name: ident => $($($p: ident),+: $t: ty);+; $($rest: tt)*) => (
    st!($name => $($($p : $t),+),+; $($rest)*);
  );
  ($name: ident => $($($p: ident),+: $($t: ty),+);+; $($rest: tt)*) => (
    st!($name => $($($p : $t),+),+; $($rest)*);
  );
  ($name: ident => $($p: ident),+: $t: ty; $($rest: tt)*) => (
    st!($name => $($p : $t),+; $($rest)*);
  );
  ($name: ident => $($p: ident),+: $($t: ty),+; $($rest: tt)*) => (
    st!($name => $($p : $t),+; $($rest)*);
  );
}

fn _read_iter<R: Read>(reader: &mut R) -> impl Iterator<Item=char> + '_ {
  reader.by_ref()
    .bytes()
    .map(|c| c.unwrap() as char)
    .skip_while(|c| c.is_whitespace())
}

#[allow(dead_code)]
fn read<F: FromStr, R: Read>(reader: &mut R) -> F {
  let str = _read_iter(reader).take_while(|c| !c.is_whitespace()).collect::<String>();
  str.parse::<F>().ok().unwrap()
}

#[allow(dead_code)]
fn read_line<F: FromStr, R: Read>(reader: &mut R) -> F {
  let str = _read_iter(reader).take_while(|c| c != &'\n').collect::<String>();
  let str = if str.ends_with('\r') { &str[0..str.len() - 1] } else { &str };
  str.parse::<F>().ok().unwrap()
}

#[allow(dead_code)]
fn read1<R: Read, T>(reader: &mut R, mut f: impl FnMut(char) -> T) -> T {
  f(_read_iter(reader).next().unwrap())
}

#[allow(dead_code)]
fn read1_line<R: Read, T>(reader: &mut R, f: impl FnMut(char) -> T) -> Vec<T> {
  _read_iter(reader).take_while(|c| c != &'\n').map(f).collect::<Vec<_>>()
}

/// 1要素読む
#[allow(unused_macros)]
macro_rules! r {
  ($stream: expr) => (read::<String, _>($stream));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));

  ($stream: expr; $t: ty) => (read::<$t, _>($stream));
  ($stream: expr; $t: ty; 1~) => (r!($stream; $t) - 1);

  ($stream: expr; $($t: ty),+) => (($(r!($stream; $t)),*));
  ($stream: expr; $($t: ty),+; 1~) => (($(r!($stream; $t) - 1),*));

  ($stream: expr; $t: ty; $n: expr) => (
    (0..$n).map(|_| r!($stream; $t)).collect::<Vec<_>>()
  );
  ($stream: expr; $t: ty; $n: expr; 1~) => (
    (0..$n).map(|_| r!($stream; $t) - 1).collect::<Vec<_>>()
  );

  ($stream: expr; $t: ty; $h: expr, $w: expr) => (
    (0..$h).map(|_| (0..$w).map(|_| r!($stream; $t)).collect::<Vec<_>>()).collect::<Vec<_>>()
  );
  ($stream: expr; $t: ty; $h: expr, $w: expr; 1~) => (
    (0..$h).map(|_| (0..$w).map(|_| r!($stream; $t) - 1).collect::<Vec<_>>()).collect::<Vec<_>>()
  );
}

/// 1文字読む
#[allow(unused_macros)]
macro_rules! r1 {
  ($stream: expr) => (read1($stream, |c| c));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));
  ($stream: expr; $f: expr) => (read1($stream, $f));
  ($stream: expr; $f: expr; ) => (r1!($stream, $f));
  ($stream: expr; $f: expr; $n: expr) => ((0..$n).map(|_| r1!($stream; $f)).collect::<Vec<_>>());
  ($stream: expr; $f: expr; $h: expr, $w: expr) => (
    (0..$h).map(|_| (0..$w).map(|_| r1!($stream; $f)).collect::<Vec<_>>()).collect::<Vec<_>>()
  );

  ($stream: expr; @$c: tt; $($tt: tt)*) => (
   r1!($stream; |c| c == stringify!($c).chars().next().unwrap(); $($tt)*)
  );
  ($stream: expr; @$c: tt/$_c: tt; $($tt: tt)*) => (r1!($stream; @$c; $($tt)*));
}

/// 1行読む
#[allow(unused_macros)]
macro_rules! rl {
  ($stream: expr) => (read_line::<String, _>($stream));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));
  ($stream: expr; $t: ty) => (read_line::<$t,  _>($stream));
  ($stream: expr; $t: ty; $n: expr) => ((0..$n).map(|_| rl!($stream; $t)).collect::<Vec<_>>());
}

macro_rules! _writes {
  ($stream: expr; $arg0: expr, $($arg: expr),*) => ({
    write!($stream, "{}", $arg0).ok();
    $(write!($stream, " {}", $arg).ok();)*
  });
}

/// 変数を出力
#[allow(unused_macros)]
macro_rules! w {
  ($stream: expr) => (write!($stream, " ").ok());
  ($stream: expr; ) => (w!($stream));
  ($stream: expr, ) => (w!($stream));

  ($stream: expr; $arg: expr) => (write!($stream, "{}", $arg).ok());
  ($stream: expr; $arg: expr, ) => (w!($stream; $arg));

  ($stream: expr; $arg0: expr, $($arg: expr),+) => (_writes!($stream; $arg0, $($arg),+));
  ($stream: expr; $arg0: expr, $($arg: expr),+, ) => (w!($stream; $arg0, $($arg),*));

  ($stream: expr, $($arg: tt)*) => (write!($stream, $($arg)*).ok());
}

/// 変数を改行付きで出力
#[allow(unused_macros)]
macro_rules! wl {
  ($stream: expr) => (writeln!($stream).ok());
  ($stream: expr, ) => (wl!($stream));
  ($stream: expr; ) => (wl!($stream));

  ($stream: expr; $arg: expr) => (writeln!($stream, "{}", $arg).ok());
  ($stream: expr; $arg: expr, ) => (wl!($stream; $arg));

  ($stream: expr; $arg0: expr, $($arg: expr),+) => ({
    _writes!($stream; $arg0, $($arg),+);
    wl!($stream)
  });
  ($stream: expr; $arg0: expr, $($arg: expr),+, ) => (wl!($stream; $arg0, $($arg),*));

  ($stream: expr, $($arg: tt)*) => (writeln!($stream, $($arg)*).ok());
}

/// ベクタを出力
#[allow(unused_macros)]
macro_rules! w_vec {
  ($stream: expr; $vec: expr) => (w_vec!($stream; $vec; $vec.len()));
  ($stream: expr; $vec: expr; $($tt: tt)*) => (w_vec!($stream; $vec => |e| e, " "; $($tt)*));

  ($stream: expr; $vec: expr => $f: expr) => (w_vec!($stream; $vec => $f; $vec.len()));
  ($stream: expr; $vec: expr => $f: expr; $($tt: tt)*) => (
    w_vec!($stream; $vec => $f, ""; $($tt)*)
  );

  ($stream: expr; $vec: expr => $f: expr, $del: expr; $n: expr) => (
    w!($stream; $f($vec[0]));
    for i in 1..$n { w!($stream, "{}{}", $del, $f($vec[i as usize])); }
    wl!($stream);
  );
  ($stream: expr; $vec: expr => $f: expr, $del: expr; $h: expr, $w: expr) => (
    for i in 0..$h { w_vec!($stream; $vec[i as usize] => $f, $del; $w); }
  );

  ($stream: expr; $vec: expr => String) => (w_vec!($stream; $vec => |c| c as char; $vec.len()));
  ($stream: expr; $vec: expr => String; $($tt: tt)*) => (
    w_vec!($stream; $vec => |c| c as char; $($tt)*)
  );

  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt) => (
    w_vec!($stream; $vec => @$c_t/$c_f; $vec.len())
  );
  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| if e {stringify!($c_t)} else {stringify!($c_f)}; $($tt)*)
  );
}

#[allow(unused_macros)]
macro_rules! wl_vec {
  ($stream: expr; $vec: expr) => (w_vec!($stream; $vec => |e| e, "\n"; $vec.len()));
  ($stream: expr; $vec: expr; $($tt: tt)*) => (w_vec!($stream; $vec => |e| e, "\n"; $($tt)*));
  ($stream: expr; $vec: expr => $f: expr) => (w_vec!($stream; $vec => $f, "\n"; $vec.len()));
  ($stream: expr; $vec: expr => $f: expr; $($tt: tt)*) => (
    w_vec!($stream; $vec => $f, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => 1~) => (wl_vec!($stream; $vec => |e| e + 1; $vec.len()));
  ($stream: expr; $vec: expr => 1~; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| e + 1, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => String) => (
    wl_vec!($stream; $vec => |c| c as char, "\n"; $vec.len())
  );
  ($stream: expr; $vec: expr => String; $($tt: tt)*) => (
    w_vec!($stream; $vec => |c| c as char, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt) => (
    wl_vec!($stream; $vec => @$c_t/$c_f; $vec.len())
  );
  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| if e {stringify!($c_t)} else {stringify!($c_f)}, "\n"; $($tt)*)
  );
}

/// 早期リターン
#[allow(unused_macros)]
macro_rules! early { ($($t: tt)*) => ({ w!($($t)*); return; }); }

/// 配列の初期化
#[allow(unused_macros)]
macro_rules! v {
  ($elem: expr; $n: expr) => (vec![$elem; $n as usize]);
  ($elem: expr; $h: expr, $w: expr) => (vec![vec![$elem; $w as usize]; $h as usize]);
}

// start: Copied Libraries

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::Borrow;

type Dict<K, V> = HashMap<K, V>;

trait DictAlias<K, V> {
  fn get_(&mut self, key: K) -> &mut V;
  fn get_or_default<'a>(&'a mut self, key: K, default: &'a V) -> &'a V;
  fn set(&mut self, key: K, f: impl FnOnce(&V) -> V) -> Entry<K, V>;
  fn set_value(&mut self, key: K, value: V) -> Entry<K, V>;
  fn set_or_default(&mut self, key: K, f: impl FnOnce(&V) -> V, default: V) -> &mut V;
  fn set_value_or_default(&mut self, key: K, value: V, default: V) -> &mut V;
}

impl<K: std::hash::Hash + Eq, V> DictAlias<K, V> for Dict<K, V> {

  fn get_(&mut self, key: K) -> &mut V { self.get_mut(&key).unwrap() }

  fn get_or_default<'a>(&'a mut self, key: K, default: &'a V) -> &'a V { self.get(&key).unwrap_or(default) }

  fn set(&mut self, key: K, f: impl FnOnce(&V) -> V) -> Entry<K, V> {
    match self.entry(key) {
      Occupied(mut e) => {
        let e_mut = e.get_mut();
        *e_mut = f(e_mut.borrow());
        Occupied(e)
      }
      Vacant(e) => { Vacant(e) }
    }
  }

  fn set_value(&mut self, key: K, value: V) -> Entry<K, V> { self.set(key, |_| value) }

  fn set_or_default(&mut self, key: K, f: impl FnOnce(&V) -> V, default: V) -> &mut V {
    self.set(key, f).or_insert(default)
  }

  fn set_value_or_default(&mut self, key: K, value: V, default: V) -> &mut V {
    self.set_value(key, value).or_insert(default)
  }
}

#[allow(unused_macros)]
macro_rules! dict {
  ($k: ty, $v: ty) => (Dict::<$k, $v>::new());
  ($k: ty, $v: ty; $keys: expr => $value: expr) => ({
    let mut dict = dict!($k, $v);
    for key in $keys { dict.insert(key, $value); }
    dict
  });
}

#[allow(unused_macros)]
macro_rules! dict_vec {
  ($k: ty, $v: ty; $keys: expr) => (dict!($k, Vec<$v>; $keys => Vec::<$v>::new()));
}

trait VecAlias<T> {
  fn get_(&mut self, key: usize) -> &T;
  fn select<U>(&self, f: impl FnMut(&T) -> U) -> Vec<U>;
}

impl<T> VecAlias<T> for Vec<T> {
  fn get_(&mut self, key: usize) -> &T {
    self.get_mut(key).unwrap()
  }
  fn select<U>(&self, mut f: impl FnMut(&T) -> U) -> Vec<U> {
    self.iter().map(|i| f(i)).collect::<Vec<_>>()
  }
}

trait VecOrdAlias<T> {
  fn asc(&mut self);
  fn desc(&mut self);
}

impl<T: Ord> VecOrdAlias<T> for Vec<T> {
  fn asc(&mut self) { self.sort_unstable(); }
  fn desc(&mut self) { self.sort_unstable_by(|i, j| j.cmp(i)); }
}

// end: Copied Libraries

use itertools::max;
// use std::cmp::min;
use std::collections::BinaryHeap;

st!(AB => a, b: usize; 1~);

#[allow(unused_variables)]
fn run<R: Read, W: Write, E: Write>(r_: &mut R, w_: &mut W, err: &mut E) {
  let (n, m) = r!(r_; usize, usize);
  let edges = rl!(r_; AB; m);

  let mut adjs = dict_vec!(usize, usize; 0..n);
  for e in edges.iter() { adjs.get_(e.a).push(e.b); }
  for e in edges.iter() { adjs.get_(e.b).push(e.a); }
  for adj in adjs.iter() { wl!(err; adj.0, adj.1.len()); }

  // let mut deps= v!(usize::MAX; n);
  let mut queue = BinaryHeap::new();
  let mut prevs = v!(usize::MAX; n);
  queue.push(0);
  prevs[0] = 0;

  while !queue.is_empty() {
    let v = queue.pop().unwrap();
    let adjs_v = adjs.get_(v);
    wl!(err, "v: {}", v);
    for &adj in adjs_v.iter() {
      wl!(err, "adj: {}", adj);
      let &prevs_adj = prevs.get_(adj);
      if prevs_adj == usize::MAX {
        queue.push(adj);
        prevs[adj] = v;
        wl!(err, "prevs[{}] = {}", adj, v);
      }
    }
  }
  if *max(prevs.iter()).unwrap() == usize::MAX { early!(w_; "No"); }
  wl!(w_; "Yes");
  let ans = &prevs[1..];
  wl_vec!(w_; ans => 1~);
}

t!(td1 => r"4 4
1 2
2 3
3 4
4 2", r"Yes
1
2
2");
t!(td2 => r"6 9
3 4
6 1
2 4
5 3
4 6
1 5
6 2
4 5
5 6", r"Yes
6
5
5
1
1");


use std::*;
use std::io::*;
use std::iter::Iterator;
use std::str::FromStr;
#[allow(unused_imports)]
use std::fmt::{Display, Formatter};

#[allow(dead_code)]
fn main() {
  let stdin = stdin();
  let r = &mut BufReader::new(stdin.lock());
  let stdout = stdout();
  let w = &mut BufWriter::new(stdout.lock());
  let stderr = stderr();
  let err = &mut BufWriter::new(stderr.lock());
  run(r, w, err);
  w.flush().unwrap();
  err.flush().unwrap();
}

macro_rules! _ft { () => (impl FnOnce(&mut Cursor<Vec<u8>>, &mut Vec<u8>, &mut Vec<u8>)); }

#[allow(dead_code)]
fn test(input: &str, output: &str, f: _ft!()) {
  let r = &mut Cursor::new(input.as_bytes().to_vec());
  let w: &mut Vec<u8> = &mut Vec::new();
  let err: &mut Vec<u8> = &mut Vec::new();
  f(r, w, err);
  let mut stderr = stderr();
  writeln!(stderr, "{}", String::from_utf8(err.to_vec()).unwrap()).unwrap();
  stderr.flush().ok();
  assert_eq!(String::from_utf8(w.to_vec()).unwrap().trim(), output.trim())
}

#[allow(unused_macros)]
macro_rules! t {
  ($f: ident => $input: expr, $output: expr) => (
    #[test]
    fn $f() { test($input, $output, run); }
  );
}

macro_rules! _display_st {
    ($f: expr; $name: expr, ) => (write!($f, "{}", $name)?);
    ($f: expr; $name: expr) => (_display_st!($f; $name, ));
    ($f: expr; $name: expr, $($rest: expr),+, ) => (
      _display_st!($f; $name);
      write!($f, " ")?;
      _display_st!($f; $($rest, )+);
    );
    ($f: expr; $name: expr, $($rest: expr),+) => (_display_st!($f; $name, $($rest, )+));
}

macro_rules! _st_iter_parse {
  ($iter: expr; $($p: ident : $t: ty),+; ) => (Self {
    $($p: $iter.next().unwrap().parse::<$t>().unwrap(), )+
  });
  ($iter: expr; $($p: ident : $t: ty),+; 1~) => (Self {
    $($p: $iter.next().unwrap().parse::<$t>().unwrap() - 1, )+
  });
}

/// 構造体を作成する
#[allow(unused_macros)]
macro_rules! st {
  ($name: ident => $($p: ident : $t: ty),+; $($rest: tt)*) => (
    struct $name { $($p : $t),+ }
    impl FromStr for $name {
      type Err = ();
      fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        let mut iter = s.split_whitespace();
        Ok(_st_iter_parse!(iter; $($p : $t),+; $($rest)*))
      }
    }
    impl Display for $name {
      fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        _display_st!(f; $(&self.$p, )+);
        Ok(())
      }
    }
  );
  ($name: ident => $($p: ident : $t: ty),+) => (st!($name => $($p : $t),+; ););

  ($name: ident => $($($p: ident),+: $t: ty);+) => (st!($name => $($($p : $t),+),+););
  ($name: ident => $($($p: ident),+: $($t: ty),+);+) => (st!($name => $($($p : $t),+),+););
  ($name: ident => $($p: ident),+: $t: ty) => (st!($name => $($p : $t),+););
  ($name: ident => $($p: ident),+: $($t: ty),+) => (st!($name => $($p : $t),+););

  ($name: ident => $($($p: ident),+: $t: ty);+; $($rest: tt)*) => (
    st!($name => $($($p : $t),+),+; $($rest)*);
  );
  ($name: ident => $($($p: ident),+: $($t: ty),+);+; $($rest: tt)*) => (
    st!($name => $($($p : $t),+),+; $($rest)*);
  );
  ($name: ident => $($p: ident),+: $t: ty; $($rest: tt)*) => (
    st!($name => $($p : $t),+; $($rest)*);
  );
  ($name: ident => $($p: ident),+: $($t: ty),+; $($rest: tt)*) => (
    st!($name => $($p : $t),+; $($rest)*);
  );
}

fn _read_iter<R: Read>(reader: &mut R) -> impl Iterator<Item=char> + '_ {
  reader.by_ref()
    .bytes()
    .map(|c| c.unwrap() as char)
    .skip_while(|c| c.is_whitespace())
}

#[allow(dead_code)]
fn read<F: FromStr, R: Read>(reader: &mut R) -> F {
  let str = _read_iter(reader).take_while(|c| !c.is_whitespace()).collect::<String>();
  str.parse::<F>().ok().unwrap()
}

#[allow(dead_code)]
fn read_line<F: FromStr, R: Read>(reader: &mut R) -> F {
  let str = _read_iter(reader).take_while(|c| c != &'\n').collect::<String>();
  let str = if str.ends_with('\r') { &str[0..str.len() - 1] } else { &str };
  str.parse::<F>().ok().unwrap()
}

#[allow(dead_code)]
fn read1<R: Read, T>(reader: &mut R, mut f: impl FnMut(char) -> T) -> T {
  f(_read_iter(reader).next().unwrap())
}

#[allow(dead_code)]
fn read1_line<R: Read, T>(reader: &mut R, f: impl FnMut(char) -> T) -> Vec<T> {
  _read_iter(reader).take_while(|c| c != &'\n').map(f).collect::<Vec<_>>()
}

/// 1要素読む
#[allow(unused_macros)]
macro_rules! r {
  ($stream: expr) => (read::<String, _>($stream));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));

  ($stream: expr; $t: ty) => (read::<$t, _>($stream));
  ($stream: expr; $t: ty; 1~) => (r!($stream; $t) - 1);

  ($stream: expr; $($t: ty),+) => (($(r!($stream; $t)),*));
  ($stream: expr; $($t: ty),+; 1~) => (($(r!($stream; $t) - 1),*));

  ($stream: expr; $t: ty; $n: expr) => (
    (0..$n).map(|_| r!($stream; $t)).collect::<Vec<_>>()
  );
  ($stream: expr; $t: ty; $n: expr; 1~) => (
    (0..$n).map(|_| r!($stream; $t) - 1).collect::<Vec<_>>()
  );

  ($stream: expr; $t: ty; $h: expr, $w: expr) => (
    (0..$h).map(|_| (0..$w).map(|_| r!($stream; $t)).collect::<Vec<_>>()).collect::<Vec<_>>()
  );
  ($stream: expr; $t: ty; $h: expr, $w: expr; 1~) => (
    (0..$h).map(|_| (0..$w).map(|_| r!($stream; $t) - 1).collect::<Vec<_>>()).collect::<Vec<_>>()
  );
}

/// 1文字読む
#[allow(unused_macros)]
macro_rules! r1 {
  ($stream: expr) => (read1($stream, |c| c));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));
  ($stream: expr; $f: expr) => (read1($stream, $f));
  ($stream: expr; $f: expr; ) => (r1!($stream, $f));
  ($stream: expr; $f: expr; $n: expr) => ((0..$n).map(|_| r1!($stream; $f)).collect::<Vec<_>>());
  ($stream: expr; $f: expr; $h: expr, $w: expr) => (
    (0..$h).map(|_| (0..$w).map(|_| r1!($stream; $f)).collect::<Vec<_>>()).collect::<Vec<_>>()
  );

  ($stream: expr; @$c: tt; $($tt: tt)*) => (
   r1!($stream; |c| c == stringify!($c).chars().next().unwrap(); $($tt)*)
  );
  ($stream: expr; @$c: tt/$_c: tt; $($tt: tt)*) => (r1!($stream; @$c; $($tt)*));
}

/// 1行読む
#[allow(unused_macros)]
macro_rules! rl {
  ($stream: expr) => (read_line::<String, _>($stream));
  ($stream: expr, ) => (r!($stream));
  ($stream: expr; ) => (r!($stream));
  ($stream: expr; $t: ty) => (read_line::<$t,  _>($stream));
  ($stream: expr; $t: ty; $n: expr) => ((0..$n).map(|_| rl!($stream; $t)).collect::<Vec<_>>());
}

macro_rules! _writes {
  ($stream: expr; $arg0: expr, $($arg: expr),*) => ({
    write!($stream, "{}", $arg0).ok();
    $(write!($stream, " {}", $arg).ok();)*
  });
}

/// 変数を出力
#[allow(unused_macros)]
macro_rules! w {
  ($stream: expr) => (write!($stream, " ").ok());
  ($stream: expr; ) => (w!($stream));
  ($stream: expr, ) => (w!($stream));

  ($stream: expr; $arg: expr) => (write!($stream, "{}", $arg).ok());
  ($stream: expr; $arg: expr, ) => (w!($stream; $arg));

  ($stream: expr; $arg0: expr, $($arg: expr),+) => (_writes!($stream; $arg0, $($arg),+));
  ($stream: expr; $arg0: expr, $($arg: expr),+, ) => (w!($stream; $arg0, $($arg),*));

  ($stream: expr, $($arg: tt)*) => (write!($stream, $($arg)*).ok());
}

/// 変数を改行付きで出力
#[allow(unused_macros)]
macro_rules! wl {
  ($stream: expr) => (writeln!($stream).ok());
  ($stream: expr, ) => (wl!($stream));
  ($stream: expr; ) => (wl!($stream));

  ($stream: expr; $arg: expr) => (writeln!($stream, "{}", $arg).ok());
  ($stream: expr; $arg: expr, ) => (wl!($stream; $arg));

  ($stream: expr; $arg0: expr, $($arg: expr),+) => ({
    _writes!($stream; $arg0, $($arg),+);
    wl!($stream)
  });
  ($stream: expr; $arg0: expr, $($arg: expr),+, ) => (wl!($stream; $arg0, $($arg),*));

  ($stream: expr, $($arg: tt)*) => (writeln!($stream, $($arg)*).ok());
}

/// ベクタを出力
#[allow(unused_macros)]
macro_rules! w_vec {
  ($stream: expr; $vec: expr) => (w_vec!($stream; $vec; $vec.len()));
  ($stream: expr; $vec: expr; $($tt: tt)*) => (w_vec!($stream; $vec => |e| e, " "; $($tt)*));

  ($stream: expr; $vec: expr => $f: expr) => (w_vec!($stream; $vec => $f; $vec.len()));
  ($stream: expr; $vec: expr => $f: expr; $($tt: tt)*) => (
    w_vec!($stream; $vec => $f, ""; $($tt)*)
  );

  ($stream: expr; $vec: expr => $f: expr, $del: expr; $n: expr) => (
    w!($stream; $f($vec[0]));
    for i in 1..$n { w!($stream, "{}{}", $del, $f($vec[i as usize])); }
    wl!($stream);
  );
  ($stream: expr; $vec: expr => $f: expr, $del: expr; $h: expr, $w: expr) => (
    for i in 0..$h { w_vec!($stream; $vec[i as usize] => $f, $del; $w); }
  );

  ($stream: expr; $vec: expr => String) => (w_vec!($stream; $vec => |c| c as char; $vec.len()));
  ($stream: expr; $vec: expr => String; $($tt: tt)*) => (
    w_vec!($stream; $vec => |c| c as char; $($tt)*)
  );

  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt) => (
    w_vec!($stream; $vec => @$c_t/$c_f; $vec.len())
  );
  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| if e {stringify!($c_t)} else {stringify!($c_f)}; $($tt)*)
  );
}

#[allow(unused_macros)]
macro_rules! wl_vec {
  ($stream: expr; $vec: expr) => (w_vec!($stream; $vec => |e| e, "\n"; $vec.len()));
  ($stream: expr; $vec: expr; $($tt: tt)*) => (w_vec!($stream; $vec => |e| e, "\n"; $($tt)*));
  ($stream: expr; $vec: expr => $f: expr) => (w_vec!($stream; $vec => $f, "\n"; $vec.len()));
  ($stream: expr; $vec: expr => $f: expr; $($tt: tt)*) => (
    w_vec!($stream; $vec => $f, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => 1~) => (wl_vec!($stream; $vec => |e| e + 1; $vec.len()));
  ($stream: expr; $vec: expr => 1~; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| e + 1, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => String) => (
    wl_vec!($stream; $vec => |c| c as char, "\n"; $vec.len())
  );
  ($stream: expr; $vec: expr => String; $($tt: tt)*) => (
    w_vec!($stream; $vec => |c| c as char, "\n"; $($tt)*)
  );

  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt) => (
    wl_vec!($stream; $vec => @$c_t/$c_f; $vec.len())
  );
  ($stream: expr; $vec: expr => @$c_t: tt/$c_f: tt; $($tt: tt)*) => (
    w_vec!($stream; $vec => |e| if e {stringify!($c_t)} else {stringify!($c_f)}, "\n"; $($tt)*)
  );
}

/// 早期リターン
#[allow(unused_macros)]
macro_rules! early { ($($t: tt)*) => ({ w!($($t)*); return; }); }

/// 配列の初期化
#[allow(unused_macros)]
macro_rules! v {
  ($elem: expr; $n: expr) => (vec![$elem; $n as usize]);
  ($elem: expr; $h: expr, $w: expr) => (vec![vec![$elem; $w as usize]; $h as usize]);
}

// start: Copied Libraries

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::Borrow;

type Dict<K, V> = HashMap<K, V>;

trait DictAlias<K, V> {
  fn get_(&mut self, key: K) -> &mut V;
  fn get_or_default<'a>(&'a mut self, key: K, default: &'a V) -> &'a V;
  fn set(&mut self, key: K, f: impl FnOnce(&V) -> V) -> Entry<K, V>;
  fn set_value(&mut self, key: K, value: V) -> Entry<K, V>;
  fn set_or_default(&mut self, key: K, f: impl FnOnce(&V) -> V, default: V) -> &mut V;
  fn set_value_or_default(&mut self, key: K, value: V, default: V) -> &mut V;
}

impl<K: std::hash::Hash + Eq, V> DictAlias<K, V> for Dict<K, V> {

  fn get_(&mut self, key: K) -> &mut V { self.get_mut(&key).unwrap() }

  fn get_or_default<'a>(&'a mut self, key: K, default: &'a V) -> &'a V { self.get(&key).unwrap_or(default) }

  fn set(&mut self, key: K, f: impl FnOnce(&V) -> V) -> Entry<K, V> {
    match self.entry(key) {
      Occupied(mut e) => {
        let e_mut = e.get_mut();
        *e_mut = f(e_mut.borrow());
        Occupied(e)
      }
      Vacant(e) => { Vacant(e) }
    }
  }

  fn set_value(&mut self, key: K, value: V) -> Entry<K, V> { self.set(key, |_| value) }

  fn set_or_default(&mut self, key: K, f: impl FnOnce(&V) -> V, default: V) -> &mut V {
    self.set(key, f).or_insert(default)
  }

  fn set_value_or_default(&mut self, key: K, value: V, default: V) -> &mut V {
    self.set_value(key, value).or_insert(default)
  }
}

#[allow(unused_macros)]
macro_rules! dict {
  ($k: ty, $v: ty) => (Dict::<$k, $v>::new());
  ($k: ty, $v: ty; $keys: expr => $value: expr) => ({
    let mut dict = dict!($k, $v);
    for key in $keys { dict.insert(key, $value); }
    dict
  });
}

#[allow(unused_macros)]
macro_rules! dict_vec {
  ($k: ty, $v: ty; $keys: expr) => (dict!($k, Vec<$v>; $keys => Vec::<$v>::new()));
}

trait VecAlias<T> {
  fn get_(&mut self, key: usize) -> &T;
  fn select<U>(&self, f: impl FnMut(&T) -> U) -> Vec<U>;
}

impl<T> VecAlias<T> for Vec<T> {
  fn get_(&mut self, key: usize) -> &T {
    self.get_mut(key).unwrap()
  }
  fn select<U>(&self, mut f: impl FnMut(&T) -> U) -> Vec<U> {
    self.iter().map(|i| f(i)).collect::<Vec<_>>()
  }
}

trait VecOrdAlias<T> {
  fn asc(&mut self);
  fn desc(&mut self);
}

impl<T: Ord> VecOrdAlias<T> for Vec<T> {
  fn asc(&mut self) { self.sort_unstable(); }
  fn desc(&mut self) { self.sort_unstable_by(|i, j| j.cmp(i)); }
}

// end: Copied Libraries

use itertools::max;
// use std::cmp::min;
use std::collections::BinaryHeap;

st!(AB => a, b: usize; 1~);

#[allow(unused_variables)]
fn run<R: Read, W: Write, E: Write>(r_: &mut R, w_: &mut W, err: &mut E) {
  let (n, m) = r!(r_; usize, usize);
  let edges = rl!(r_; AB; m);

  let mut adjs = dict_vec!(usize, usize; 0..n);
  for e in edges.iter() { adjs.get_(e.a).push(e.b); }
  for e in edges.iter() { adjs.get_(e.b).push(e.a); }
  for adj in adjs.iter() { wl!(err; adj.0, adj.1.len()); }

  // let mut deps= v!(usize::MAX; n);
  let mut queue = BinaryHeap::new();
  let mut prevs = v!(usize::MAX; n);
  queue.push(0);
  prevs[0] = 0;

  while !queue.is_empty() {
    let v = queue.pop().unwrap();
    let adjs_v = adjs.get_(v);
    wl!(err, "v: {}", v);
    for &adj in adjs_v.iter() {
      wl!(err, "adj: {}", adj);
      let &prevs_adj = prevs.get_(adj);
      if prevs_adj == usize::MAX {
        queue.push(adj);
        prevs[adj] = v;
        wl!(err, "prevs[{}] = {}", adj, v);
      }
    }
  }
  let
  if *max(prevs.iter()).unwrap() == usize::MAX { early!(w_; "No"); }
  wl!(w_; "Yes");
  let ans = &prevs[1..];
  wl_vec!(w_; ans => 1~);
}

t!(td1 => r"4 4
1 2
2 3
3 4
4 2", r"Yes
1
2
2");
t!(td2 => r"6 9
3 4
6 1
2 4
5 3
4 6
1 5
6 2
4 5
5 6", r"Yes
6
5
5
1
1");


#![allow(non_snake_case)]
use std::io::*;
use std::str::FromStr;

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn main() {
    let n: usize = read();
    let m: usize = read();
    let mut v: Vec<Vec<usize>> = vec![vec![]; n + 1];
    let mut shortest: Vec<i64> = vec![0; n + 1];
    let mut ansArr: Vec<usize> = vec![0; n + 1];
    shortest[1] = -1000;
    for _ in 0..m {
        let a: usize = read();
        let b: usize = read();
        &v[a].push(b);
        &v[b].push(a);
        if a == 1 {
            shortest[b] = 1;
            ansArr[b] = 1;
        } else if b == 1 {
            ansArr[a] = 1;
            shortest[a] = 1;
        }
        let mut aaaa = |index: usize| {
            if ansArr[index] != 0 {
                for i in &v[index] {
                    if shortest[*i] == 0 {
                        shortest[*i] = shortest[index] + 1;
                        ansArr[*i] = index;
                    } else {
                        if shortest[*i] > shortest[index] + 1{
                            shortest[*i] = shortest[index] + 1;
                            ansArr[*i] = index;
                        } else if shortest[*i] == shortest[index] + 1 {
                            // 特に意味ないけど同率なら小さい番号
                            if index > *i{
                                ansArr[*i] = index;
                            }
                        }
                    }
                }
                v[index].clear();
            }
        };
        aaaa(a);
        aaaa(b);
    }

    print!("Yes\n");
    for i in 2..n + 1 {
        print!("{}\n", ansArr[i]);
    }
}


import Foundation
let main: () = {
    let (N, M) = *listOfInt()
    var G = [[Int]](repeating: [Int](), count: N)
    repeate(M) { _ in
        let (a, b) = *listOfInt(-1)
        G[a].append(b)
        G[b].append(a)
    }
    var D = IntArray(N) { -1 }
    var Q = [0]
    while !Q.isEmpty {
        var next = [Int]()
        for q in Q {
            for v in G[q] {
                if (D[v] != -1) { continue }
                D[v] = q
                next += v
            }
        }
        Q = next
    }

    let yes = D.all { $0 != -1}
    print(yes ? "Yes" : "No")
    if !yes { return }

    for n in 1 ..< N {
        print(D[n] + 1)
    }
}()

struct Queue<T> {
    var elements = [T]()
    var isEmpty: Bool { elements.isEmpty }
    var count: Int { elements.count }
    mutating func enqueue(_ t: T) { elements.append(t) }
    mutating func dequeue() -> T? { if !isEmpty { return elements.removeFirst() } else { return nil } }
    mutating func peek() -> T? { if !isEmpty { return elements.first } else { return nil } }
    var description: String { elements.description }
}

//----------------------------------

let dx = [1, 0, -1, 0] //[1, 0, -1, 0, -1,  1, -1, 1]
let dy = [0, 1, 0, -1] //[0, 1, 0, -1, -1, -1,  1, 1]

@inlinable func gcd(_ a: Int, _ b: Int) -> Int { (b > 0) ? gcd(b, a % b) : a }
@inlinable func lcm(_ a: Int, _ b: Int) -> Int { a / gcd(a, b) * b }

//----------------------------------

infix operator  =~ : ComparisonPrecedence
infix operator !=~ : ComparisonPrecedence
func =~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { !(right ~= left) }
func =~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { !(right ~= left) }

func =~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { right.contains(left) }
func !=~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { !right.contains(left) }

infix operator /^ : MultiplicationPrecedence
infix operator /^= : AssignmentPrecedence
func /^ <T: FixedWidthInteger>(left: T, right: T) -> T { (left + (right - 1)) / right }
func /^= <T: FixedWidthInteger>(left: inout T, right: T) { left = (left + (right - 1)) / right }

@inlinable func chmax<T: Comparable>(_ m: inout T, _ q: T) { if (m < q) { m = q } }
@inlinable func chmin<T: Comparable>(_ m: inout T, _ q: T) { if (m > q) { m = q } }
@inlinable func chRmax<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m < q) { m = q; return true } else { return false } }
@inlinable func chRmin<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m > q) { m = q; return true } else { return false } }

prefix operator *
prefix func * <T> (a: [T]) -> (T, T) { (a[0], a[1]) }
prefix func * <T> (a: [T]) -> (T, T, T) { (a[0], a[1], a[2]) }
prefix func * <T> (a: [T]) -> (T, T, T, T) { (a[0], a[1], a[2], a[3]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4], a[5]) }

func printErr(_ str: String, terminator: String = "\n") {
    let s = str + terminator
    FileHandle.standardError.write(s.data(using: .utf8)!)
    FileHandle.standardError.synchronizeFile()
}

@inlinable func next() -> String { readLine()! }
@inlinable func nextInt() -> Int { Int(next())! }
@inlinable func nextDouble() -> Double { Double(next())! }
@inlinable func listOfString() -> [String] { next().split(separator: " ").map(String.init) }
@inlinable func listOfInt() -> [Int] { listOfString().map { Int($0)! } }
@inlinable func listOfInt(_ offset: Int = 0) -> [Int] { listOfString().map { Int($0)! + offset } }
@inlinable func listOfInt(_ offsets: Int ...) -> [Int] { listOfString().enumerated().map { Int($0.element)! + offsets[$0.offset % offsets.count] } }
@inlinable func listOfDouble(_ offset: Double = 0.0) -> [Double] { listOfString().map { Double($0)! + offset } }
@inlinable func listOfDouble(_ offsets: Double ...) -> [Double] { listOfString().enumerated().map { Double($0.element)! + offsets[$0.offset % offsets.count] } }

extension Int {
    init(s: String) { self.init(s)! }
    var isEven: Bool { self.isMultiple(of: 2) }
    var isOdd: Bool { !self.isEven }
    var isTrue: Bool { self != 0 }
    var isFalse: Bool { !self.isTrue }
    var toString: String { String(self) }
    var toChar: Character { Character(UnicodeScalar(UInt8(self))) }
}
func + (left: Int, right: Bool) -> Int { left + (right ? 1 : 0) }
extension Character {
    var asciiCode: Int { Int(self.asciiValue!) }
    var string: String { String(self) }
}
extension String {
    @inlinable subscript (position: Int) -> Character { self[self.index(self.startIndex, offsetBy: position)] }
    @inlinable func repeate(_ times: Int) -> String { String(repeating: self, count: times) }
    //  @inlinable subscript (n: Int) -> String { String(self[self.index(self.startIndex, offsetBy: n)]) }
    //  @inlinable subscript (n: Int) -> Int { Int(self[self.index(self.startIndex, offsetBy: n)].asciiValue!) }
    var toInt: Int { Int(self)! }
}
extension String { // VB like
    @inlinable func _index(_ position: Int) -> String.Index! {
        if !(0 ..< self.count ~= position) { return nil }
        return self.index(self.startIndex, offsetBy: position)
    }
    @inlinable func mid(from index: Int, length: Int) -> String! {
        if let startPosition = self._index(index) {
            if let endPosition = self._index(index + length - 1) {
                return String(self[startPosition...endPosition])
            } else {
                let endPosition = self.index(before: self.endIndex)
                return String(self[startPosition...endPosition])
            }
        }
        return ""
    }
    @inlinable func left(_ length: Int) -> String { String(self.prefix(length)) }
    @inlinable func right(_ length: Int) -> String { String(self.suffix(length)) }
}

extension Dictionary {
    @inlinable mutating func getOrSet(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored }
        else {
            let newValue = defaultValue()
            self[key] = newValue
            return newValue
        }
    }
    @inlinable mutating func getOrElse(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored } else { return defaultValue() }
    }
    @inlinable func containsKey(_ key: Key) -> Bool { self.keys.contains(key) }
}

extension Set {
    static func += (left: inout Set<Element>, right: Element) { left.insert(right) }
    static func -= (left: inout Set<Element>, right: Element) { left.remove(right) }
}

extension Array {
    static func += (left: inout Array<Element>, right: Element) { left.append(right) }
    init(_ size: Int, _ initValue: ((Int) -> Element)) {
        self = [Element]()
        for index in 0 ..< size {
            let value = initValue(index)
            self.append(value)
        }
    }
    init(_ size: Int, _ initValue: (() -> Element)) {
        self = [Element]()
        for _ in 0 ..< size {
            let value = initValue()
            self.append(value)
        }
    }
}
typealias IntArray = Array<Int>
typealias DoubleArray = Array<Double>
typealias BoolArray = Array<Bool>
typealias StringArray = Array<String>

extension Array where Element == Int {
    init(_ size: Int) {
        self = [Element](repeating: 0, count: size)
    }
}
extension Array where Element == Double {
    init(_ size: Int) {
        self = [Element](repeating: 0.0, count: size)
    }
}
extension Array where Element == Bool {
    init(_ size: Int) {
        self = [Element](repeating: false, count: size)
    }
}
extension Array where Element == String {
    init(_ size: Int) {
        self = [Element](repeating: "", count: size)
    }
}

extension Array {
    @inlinable func count(_ predicate: ((Element) -> Bool)) -> Int {
        var cnt = 0; for e in self { if (predicate(e)) { cnt += 1 } }
        return cnt
    }
    @inlinable func groupBy<K>(_ keySelector: (Element) -> K) -> [K : [Element]] {
        var destination = [K : [Element]]()
        for element in self {
            let key = keySelector(element)
            var list = destination.getOrSet(key) { [Element]() }
            list.append(element)
            destination[key] = list
        }
        return destination
    }
    @inlinable func groupByIndexed<K>(_ keySelector: (Element) -> K) -> [K : [Int]] {
        var destination = [K : [Int]]()
        for element in self.enumerated() {
            let key = keySelector(element.element)
            var list = destination.getOrSet(key) { [Int]() }
            list.append(element.offset)
            destination[key] = list
        }
        return destination
    }
}

extension Array {
    func binarySearch(_ element: Element, by compare: (Element, Element) -> Int, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            let cmp = compare(midVal, element)
            if (cmp < 0) { low = mid + 1 }          //-1
            else if (0 < cmp) { high = mid - 1 }    // 1
            else { return mid } // key found        // 0
        }
        return -(low + 1)  // key not found
    }
}
extension Array where Element : Comparable {
    func binarySearch(_ element: Element, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            if (midVal < element) { low = mid + 1 }
            else if (midVal > element) { high = mid - 1 }
            else { return mid } // key found
        }
        return -(low + 1)  // key not found
    }
}

extension Array where Element == Int {
    @inlinable func distinct() -> [Element] {
        var set = Set<Element>(), ary = [Element]()
        for n in self.indices { if !set.contains(self[n]) { ary.append(self[n]); set.insert(self[n]) } }
        return ary
    }
    @inlinable func any(_ predicate: (Element) -> Bool) -> Bool {
        var any = false; for element in self { if predicate(element) { any = true } }
        return any
    }
    @inlinable func all(_ predicate: (Element) -> Bool) -> Bool {
        self.allSatisfy(predicate)
    }
    @inlinable func sum() -> Element { self.reduce(0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}

extension Array where Element == Double {
    @inlinable func sum() -> Element { self.reduce(0.0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0.0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}
extension Array where Element == String {
    @inlinable func toIntDouble() -> (Int, Double) { (Int(self[0])!, Double(self[1])!) }
    @inlinable func toIntString() -> (Int, String) { (Int(self[0])!, self[1]) }
    @inlinable func toIntIntString() -> (Int, Int, String) { (Int(self[0])!, Int(self[1])!, self[2]) }
}

@inlinable func repeate(_ times1: Int, _ action: () -> Void) {
    for _ in 0 ..< times1 { action() }
}
@inlinable func repeate(_ times1: Int, _ action: (Int) -> Void) {
    for index1 in 0 ..< times1 {
        action(index1)
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ action: (Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            action(index1, index2)
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ action: (Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                action(index1, index2, index3)
            }
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ times4: Int, _ action: (Int, Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                for index4 in 0 ..< times4 {
                    action(index1, index2, index3, index4)
                }
            }
        }
    }
}

func measureTimeSeconds(block: (() -> Void)) -> Double {
    let startTime = Date()
    block()
    let duration = -startTime.timeIntervalSinceNow
    return duration
}

extension Array {
    func permutation (_ length: Int) -> [[Element]] {
        if length < 0 || length > self.count {
            return []
        } else if length == 0 {
            return [[]]
        } else {
            var permutations: [[Element]] = []
            let combinations = combination(length)
            for combination in combinations {
                var endArray: [[Element]] = []
                var mutableCombination = combination
                permutations += self.permutationHelper(length, array: &mutableCombination, endArray: &endArray)
            }
            return permutations
        }
    }
    private func permutationHelper(_ n: Int, array: inout [Element], endArray: inout [[Element]]) -> [[Element]] {
        if n == 1 {
            endArray += [array]
        }
        for i in 0 ..< n {
            _ = permutationHelper(n - 1, array: &array, endArray: &endArray)
            let j = n % 2 == 0 ? i : 0
            let temp: Element = array[j]
            array[j] = array[n - 1]
            array[n - 1] = temp
        }
        return endArray
    }
    /**
     - parameter length:
     - returns: Returns all of the combinations in the array of the given length
     */
    func combination (_ length: Int) -> [[Element]] {
        if length < 0 || length > self.count {
            return []
        }
        var indexes: [Int] = (0 ..< length).reduce([]) {$0 + [$1]}
        var combinations: [[Element]] = []
        let offset = self.count - indexes.count
        while true {
            var combination: [Element] = []
            for index in indexes {
                combination.append(self[index])
            }
            combinations.append(combination)
            var i = indexes.count - 1
            while i >= 0 && indexes[i] == i + offset {
                i -= 1
            }
            if i < 0 {
                break
            }
            i += 1
            let start = indexes[i-1] + 1
            for j in (i - 1) ..< indexes.count {
                indexes[j] = start + j - i + 1
            }
        }
        return combinations
    }
    /**
     - parameter length: The length of each permutations
     - returns: All of the permutations of this array of a given length, allowing repeats
     */
    func repeatedPermutation(_ length: Int) -> [[Element]] {
        if length < 1 {
            return []
        }
        var indexes: [[Int]] = []
        indexes.repeatedPermutationHelper([], length: length, arrayLength: self.count, indexes: &indexes)
        return indexes.map({ $0.map({ i in self[i] }) })
    }
    private func repeatedPermutationHelper(_ seed: [Int], length: Int, arrayLength: Int, indexes: inout [[Int]]) {
        if seed.count == length {
            indexes.append(seed)
            return
        }
        for i in (0 ..< arrayLength) {
            var newSeed: [Int] = seed
            newSeed.append(i)
            self.repeatedPermutationHelper(newSeed, length: length, arrayLength: arrayLength, indexes: &indexes)
        }
    }
}


let first = readLine()!.split(separator: " ")
let N = Int(first[0])!
let M = Int(first[1])!

var graph: [[Int]] = .init(repeating: [], count: N)

for i in 0..<M {
  let line = readLine()!.split(separator: " ")
  let A = Int(line[0])!
  let B = Int(line[1])!
  graph[A-1].append(B-1)
  graph[B-1].append(A-1)
}

var anchor: [Int] = .init(repeating: -1, count: N)
var fixed = 0

var queue: [Int] = [0]

while !queue.isEmpty {
  var tmp: [Int] = []
  for top in queue {
  	for nei in graph[top] {
      if anchor[nei] == -1 {
        fixed += 1
        anchor[nei] = top
        tmp.append(nei)
      }
    }
  }
  queue = tmp
}

if fixed == N - 1 {
  print("No")
} else {
  print("Yes")
  for i in 1..<N {
    print(anchor[i] + 1)
  }
}


import Foundation

func readInt() -> [Int] {
    return readLine()!.split(separator: " ").map { Int($0)! }
}

func main() {
    let line = readInt()
    let N = line[0]
    let M = line[1]

    var graph = (0...N).map { _ in [Int]() }
    for _ in (1...M) {
        let ab = readInt()
        let a = ab[0]
        let b = ab[1]
        graph[a].append(b)
        graph[b].append(a)
    }

    var ans = [Int](repeating: -1, count: N + 1)
    var q = [1]
    while !q.isEmpty {
        var q_ = [Int]()
        for u in q {
            for v in graph[u] {
                guard ans[v] == -1 else { continue }
                ans[v] = u
                q_.append(v)
            }
        }
        q = q_
    }
    print("Yes")
    for i in ans[2...] {
        print(i)
    }
}

main()


import Foundation

func readInt() -> [Int] {
    return readLine()!.split(separator: " ").map { Int($0)! }
}

func main() {
    let line = readInt()
    let N = line[0]
    let M = line[1]

    var graph = (0...M).map { _ in [Int]() }
    for _ in (1...M) {
        let ab = readInt()
        let a = ab[0]
        let b = ab[1]
        graph[a].append(b)
        graph[b].append(a)
    }

    var ans = [Int](repeating: -1, count: N + 1)
    var q = ArraySlice<Int>()
    q.append(1)
    while let u = q.popFirst() {
        for v in graph[u] {
            guard ans[v] == -1 else { continue }
            ans[v] = u
            q.append(v)
        }
    }

    if ans[2...].contains(-1) {
        print("No")
        return
    }

    print("Yes")
    for i in ans[2...] {
        print(i)
    }

}

main()