Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math notebooks: it is time to sort them out. This time he found an old dusty graph theory notebook with a description of a graph.

It is an undirected weighted graph on n vertices. It is a complete graph: each pair of vertices is connected by an edge. The weight of each edge is either 0 or 1; exactly m edges have weight 1, and all others have weight 0.

Since Ujan doesn't really want to organize his notes, he decided to find the weight of the minimum spanning tree of the graph. (The weight of a spanning tree is the sum of all its edges.) Can you find the answer for Ujan so he stops procrastinating?

Input

The first line of the input contains two integers n and m (1 ≤ n ≤ 10^5, 0 ≤ m ≤ min((n(n-1))/(2),10^5)), the number of vertices and the number of edges of weight 1 in the graph. 

The i-th of the next m lines contains two integers a_i and b_i (1 ≤ a_i, b_i ≤ n, a_i ≠ b_i), the endpoints of the i-th edge of weight 1.

It is guaranteed that no edge appears twice in the input.

Output

Output a single integer, the weight of the minimum spanning tree of the graph.

Examples

Input


6 11
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6


Output


2


Input


3 0


Output


0

Note

The graph from the first sample is shown below. Dashed edges have weight 0, other edges have weight 1. One of the minimum spanning trees is highlighted in orange and has total weight 2.

<image>

In the second sample, all edges have weight 0 so any spanning tree has total weight 0.
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeSet;

public final class CF_599_D1_B2
{


	static boolean verb=true;
	static void log(Object X){if (verb) System.err.println(X);}
	static void log(Object[] X){if (verb) {for (Object U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X){if (verb) {for (int U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X,int L){if (verb) {for (int i=0;i<L;i++) System.err.print(X[i]+" ");System.err.println("");}}
	static void log(long[] X){if (verb) {for (long U:X) System.err.print(U+" ");System.err.println("");}}

	static void logWln(Object X){if (verb) System.err.print(X);}
	static void info(Object o){	System.out.println(o);}
	static void output(Object o){outputWln(""+o+"\n");	}
	static void outputWln(Object o){try {out.write(""+ o);} catch (Exception e) {}}

	static long mod=1000000007;

	// Global vars
	static BufferedWriter out;
	static InputReader reader;


	static class Composite implements Comparable<Composite>{
		int idx;
		int v;

		public int compareTo(Composite X) {
			if (v!=X.v)
				return v-X.v;
			return idx-X.idx;


		}

		public Composite(int idx, int v) {
			this.idx = idx;
			this.v = v;
		}



	}

	static void test() {
		log("testing");

		log("done");

	}

	static boolean compare(ArrayList<Integer> la,ArrayList<Integer> lb) {
		if (la.size()!=lb.size())
			return  false;
		int L=la.size();
		for (int i=0;i<L;i++)
			if (la.get(i)!=lb.get(i))
				return false;
		return true;
	}


	static int connect;
	static int[] stack;
	static int[] torem;;
	static int time;
	static int[] tm;
	static boolean[] visited;
	static int res;
	static int[] target;

	static void doFull(int u,ArrayList<Integer>[] friends,HashSet<Integer> all,int symbol) {
		int st=0;
		stack[st++]=u;


		while (st>0) {
			time++;
			int v=stack[st-1];
			st--;
			int tr=0;

			for (int x:friends[v]) {
				tm[x]=time;
			}
			for (int w:all) {
				if (tm[w]<time) {
					visited[w]=true;
					target[w]=symbol;
					torem[tr++]=w;
					stack[st++]=w;
					connect++;
				}
			}
			// remove
			while (tr>0) {
				int w=torem[tr-1];
				tr--;
				all.remove(w);
			}
		}

	}

	static void process() throws Exception {


		//arrayTest();

		out = new BufferedWriter(new OutputStreamWriter(System.out));
		reader = new InputReader(System.in);


		int n=reader.readInt();
		int m=reader.readInt();
		ArrayList<Integer>[] enemy=new ArrayList[n];
		ArrayList<Integer>[] friends=new ArrayList[n];

		for (int u=0;u<n;u++) {
			enemy[u]=new ArrayList<Integer>();
			friends[u]=new ArrayList<Integer>();

		}

		int[] cnt=new int[n];

		for (int i=0;i<m;i++) {
			int u=reader.readInt()-1;
			int v=reader.readInt()-1;
			enemy[u].add(v);
			enemy[v].add(u);
			cnt[u]++;
			cnt[v]++;
		}



		Composite[] ar=new Composite[n];
		for (int u=0;u<n;u++) {
			Collections.sort(friends[u]);
			ar[u]=new Composite(u,cnt[u]);
		}
		Arrays.sort(ar);

		int LM=(n-1)/2;

		// zer is a symbol
		int zer=1;

		time=1;
		
		stack=new int[n];
		visited=new boolean[n];
		target=new int[n];
		Arrays.fill(target, -1);
		tm=new int[n];
		connect=0;
		// start by putting all below LM in the same group, which is zer

		ArrayList<Integer> cand=new ArrayList<Integer>();
		for (int u=0;u<n;u++) {
			if (cnt[u]<=LM) {
				target[u]=zer;
				//log("puttint in zer:"+u);
				connect++;
			} else {
				time++;
				cand.add(u);
				for (int v:enemy[u])
					tm[v]=time;
				for (int v=0;v<n;v++) {
					if (tm[v]<time) {
						friends[u].add(v);
					}
				}
			}
		}

		
		//log("cand size:"+cand.size());
		res=0;
		if (connect==0)
			res=-1;

		for (int u:cand) {
			if (!visited[u]) {
				//log("processing u:"+u);
				boolean gozer=false;
				int r=0;
				int w=0;
				visited[u]=true;
				stack[w++]=u;
				while (r<w) {
					int a=stack[r++];
					//log("processing a:"+a);
					for (int b:friends[a]) {
						if (target[b]==zer) {
							gozer=true;
							//log("found gozer for a:"+a+" through b:"+b);
						}
						else {
							if (!visited[b]) {
								visited[b]=true;
								stack[w++]=b;
								//log("stacking b:"+b);
							}
						}
					}
				}
				if (!gozer) {
					res++;
					
				}
				for (int t=0;t<w;t++) {
					int v=stack[t];
					target[v]=zer;
				}

			}
		}




		
		output(res);

		try {
			out.close();
		} catch (Exception e) {
		}

	}





	public static void main(String[] args) throws Exception {
		process();

	}

	static final class InputReader {
		private final InputStream stream;
		private final byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		private int read() throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read(buf);
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public final String readString() throws IOException {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			StringBuilder res = new StringBuilder();
			do {
				res.append((char) c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public final int readInt() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			int res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		public final long readLong() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			long res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

}