open Batteries
open Printf

let ($) g f x = g (f x)

let swap = Tuple2.swap

let s2i = int_of_string
let i2s = string_of_int
let s2f = float_of_string
let f2s = string_of_float
let f2i = int_of_float
let i2f = float_of_int 

let c2a = int_of_char
let a2c = char_of_int

let c2i c = c2a c - 48
let i2c i = a2c (i + 48)

let c2s = String.of_char
let s2cl = String.to_list
let cl2s = String.of_list

let puts s = print_endline s
let putw ?yn:(yn=("Yes", "No")) b = puts (if b then fst yn else snd yn)
let puti i = puts @@ i2s i



module StaleList = struct
  include List

  let nmem x l = not @@ mem x l

  let len = length
  let size = length
  let nempty l = not @@ is_empty l

  let hdop l = if nempty l then Some (hd l) else None

  (* let taker = drop *)
  let takewh = take_while

  (* let dropr = take *)
  let dropwh = drop_while

  let split_by = span

  let chunk = ntake

  let foldl = fold_left
  let foldli = fold_lefti
  let foldr f z l = fold_right f l z
  let foldri f z l = fold_righti f l z

  let partition_to_map f l =
    foldr (fun x m -> Map.modify_opt (f x) (function
      | None -> Some [x] 
      | Some [] -> Some [x] 
      | Some vl -> Some (x::vl)) m) Map.empty l;;

  let scanl f z ls =
    let rec loop acl acc = function
      | [] -> rev acl
      | h::t ->
        let r = f acc h in
        loop (r::acl) r t
    in loop [] z ls

  let scanr f z ls =
    let rec loop acl acc = function
      | [] -> acl 
      | h::t ->
        let r = f h acc in
        loop (r::acl) r t
    in loop [] z (rev ls)

  (* let scanli = scan_lefti *)
  (* let scanri = scan_righti *)
  
  let flatmap = concat_map

  let zipf = map2
  let zipfi = map2i

end

module L = StaleList

module StaleArray = struct
  include Array 

  let nmem x l = not @@ mem x l

  let len = length
  let size = length
  let is_empty r = len r = 0
  let nempty r = len r > 0

  let take n r = left r n
  let taker n r = right r n

  let takeb x r =
    let l = len r in
    let rec loop i =
      if i >= l then r
      else if r.(i) = x then take i r
      else loop (i + 1)
    in loop 0
     
  (* let takewh = take_while *)

  let drop n r = tail r n
  let dropr n r = take ((len r) - n) r
  (* let dropwh = drop_while *)

  let index_of x r =
    let l = len r in
    let rec loop i =
      if i >= l then None
      else if r.(i) = x then Some i
      else loop (i + 1)
    in loop 0

  (* let split_by = span *)

  (* let chunk = ntake *)

  let foldl = fold_left
  let foldli = fold_lefti
  let foldr f z l = fold_right f l z
  let foldri f z l = fold_righti f l z

  (* let partition_to_map f l = *)
  (*   foldr (fun x m -> Map.modify_opt (f x) (function *)
  (*     | None -> Some [x]  *)
  (*     | Some [] -> Some [x]  *)
  (*     | Some vl -> Some (x::vl)) m) Map.empty l;; *)

  (* let scanl = scan_left *)
  (* let scanli = scan_lefti *)
  (* let scanr = scan_right *)
  (* let scanri = scan_righti *)
  
  let concat2 = append
  
  let flatmap (f : 'a -> 'b array) a =
    map f a |> enum |> L.of_enum |> concat

  let zipf = map2
  (* let zipfi = map2i *)

end

module A = StaleArray

module StaleString = struct
  include String

  let len = length

  let replace_chars = map
  let map = replace

  let maptol f s = L.map f (s2cl s)
  let maptoli f s = L.map f (s2cl s)

  let zipf f a b = L.zipf f (s2cl a) (s2cl b)
  let zipfi f a b = L.zipfi f (s2cl a) (s2cl b)

  let mkstr f sep ls =
    L.foldl (fun acc x -> acc ^ sep ^ (f x)) (f @@ L.hd ls) (List.tl ls)

end

module S = StaleString

let spsp s = S.split_on_char ' ' s


module StaleSortedSet = struct
  include Set

  module Make (Ord : Set.OrderedType) = struct
    include Set.Make(Ord)

    let nempty st = not @@ is_empty st
    let sing = singleton
    let nmem x st = not @@ mem x st

    let foldl f s z = fold (fun x a -> f a x) z s

    let size = cardinal
  end

  let nempty st = not @@ is_empty st
  let sing = singleton
  let nmem x st = not @@ mem x st

  let foldl f s z = fold (fun x a -> f a x) z s

  let size = cardinal
end

module Ss = StaleSortedSet

module StaleSortedMap  = struct
  include Map

  module Make (Ord : Map.OrderedType) = struct
    include Map.Make(Ord)

    let nempty st = not @@ is_empty st
    let sing = singleton
    let nmem x st = not @@ mem x st

    let get = find
    let get_or x d m = find_default d x m

    let size = cardinal
  end

  let nempty st = not @@ is_empty st
  let sing = singleton
  let nmem x st = not @@ mem x st

  let get = find
  let get_or x d m = find_default d x m

  let size = cardinal
end

module Ms = StaleSortedMap


module StaleRange = struct

  type t = Range of int * int

  let make lb ub = Range (lb, ub)

  let to_list r =
    let Range (lb, ub) = r in
    L.make (ub - lb) ((+) lb) 

  let to_array r =
    let Range (lb, ub) = r in
      A.make (ub - lb) ((+) lb)

  let iter r f = 
    let Range (lb, ub) = r in
    for i = lb to ub do f i done

  let iter2 r1 r2 f =
    let Range (lb1, ub1) = r1 and Range (lb2, ub2) = r2 in
      for i = lb1 to ub2 do
        for j = lb2 to ub2 do
          f i j
        done
      done
end

module R = StaleRange

let (--) lb ub = R.make lb ub
let (--^) lb ub = R.make lb (ub - 1)

module StaleGenericAlgorithms = struct

  let set_power ls =
    let rec loop ls pls =
      match ls with
      | [] -> pls
      | hd::tl -> loop tl (L.flatmap (fun p -> [p; hd::p]) pls)
    in loop ls [[]]

  let rec bsearch_max_int f lb ub =
    if lb >= ub then (if f lb then lb else (lb - 1))
    else (
      let m = (lb + ub) / 2 in
      if f m then bsearch_max_int f (m + 1) ub
      else bsearch_max_int f lb m
    )

  let partial_sum n ls =
    let rec loop s k = function
      | [] -> s
      | h::t ->
        if k >= n then s
        else loop (s + h) (k + 1) t
    in
    loop 0 0 ls

end

module Gal = StaleGenericAlgorithms

let rds () = read_line ()

let rdi () = s2i @@ rds ()

let rdhs () = spsp @@ rds ()
let rdhi () = rdhs () |> L.map s2i

let rdhf () = rdhs () |> L.map s2f

let rdf2 () = match rdhf () with
| a::b::_ -> (a, b)
| _ -> (0., 0.)

let rdf3 () = match rdhf () with
| a::b::c::_ -> (a, b, c)
| _ -> (0., 0., 0.)

let rdf4 () = match rdhf () with
| a::b::c::d::_ -> (a, b, c, d)
| _ -> (0., 0., 0., 0.)

let rds2 () = match rdhs () with
  | a::b::_ -> (a, b)
  | _ -> ("", "")

let rdi2 () = match rdhi () with
  | a::b::_ -> (a, b)
  | _ -> (0, 0)

let rdi3 () = match rdhi () with
| a::b::c::_ -> (a, b, c)
| _ -> (0, 0, 0)

let rdi4 () = match rdhi () with
| a::b::c::d::_ -> (a, b, c, d)
| _ -> (0, 0, 0, 0)

let rdi5 () = match rdhi () with
| a::b::c::d::e::_ -> (a, b, c, d, e)
| _ -> (0, 0, 0, 0, 0)

let rdv n rf =
  let rec loop n =
    if n <= 0 then []
    else (
      let s = rf () in
      s::(loop (n - 1))
    )
  in loop n

let rdvi n = rdv n rdi
let rdvi2 n = rdv n rdi2
let rdvi3 n = rdv n rdi3
let rdvi4 n = rdv n rdi4


let print_list aa = 
  printf "[ "; aa |> L.iter (fun a -> printf "%d " a); puts "]"

let print_array aa = 
  printf "[ "; aa |> A.iter (fun a -> printf "%d " a); puts "]"

let print_carray aa = 
  printf "[ "; aa |> A.iter (fun a -> printf "%c " a); puts "]"

let print_matrix mat =
  puts "----";
  mat |> A.iter (fun r -> print_carray r);
  puts "----"


let rec pow_mod x e m =
  let rec loop a e' =
    if e' = 0 then a mod m
    else loop ((a * x) mod m) (e'-1)
  in
  loop 1 e

let ext_euclid a b =
  let rec next (r0, s0, t0) (r1, s1, t1) =
    match r1 with
    | 0 -> (r0, s0, t0)
    | r2 ->
      let q = r0 / r1 in
      next (r1, s1, t1) (r0 - q * r1, s0 - q * s1, t0 - q * t1)
  in
  if a < b then
    let (g, y, x) = next (b, 1, 0) (a, 0, 1) in (g, x, y)
  else
    next (a, 1, 0) (b, 0, 1)

let modinv x m =
  let (g, y, z) = ext_euclid x m in
  match g with
  | 1 -> y mod m
  | _ -> invalid_arg "Not relatively prime"
    
let rec fact_mod x m =
  let rec loop a x' =
    if x' <= 0 then a
    else loop ((x' * a) mod m) (x' - 1)
  in loop 1 x

let binom_mod n k m =
  let a = fact_mod n m in
  let b = fact_mod k m in
  let c = fact_mod (n - k) m in
  (a * modinv (b * c) m) mod m


module StaleFFT = struct

  let complex_cooley_tukey ps ar =

    let rec part e d ba =
     ()
    in

  ()
end


module StaleGraph = struct

  type iset_t = int Ss.t
  type 'a v_t = { i : int; nb : iset_t; data : 'a }
  type 'a t = 'a v_t array

  let empty nv vd =
    A.init (nv + 1) (fun i -> { i = i; nb = Ss.empty; data = vd })

  let add_edge (e : int * int) g =
    let (v1, v2) = e in
    g.(v1) <- { g.(v1) with nb = Ss.add v2 g.(v1).nb };
    g

  let add_uedge e g =
    add_edge e @@ add_edge (swap e) g

  let from_edges nv vd es =
    es |> L.foldl (fun g e -> add_edge e g) (empty nv vd)

  let from_uedges nv vd es =
    es |> L.foldl (fun g e -> add_uedge e g) (empty nv vd)

  let setd g v d = g.(v.i) <- { g.(v.i) with data = d }
  let getd g v = g.(v.i).data

  let setdi g i d = g.(i) <- { g.(i) with data = d }
  let getdi g i = g.(i).data

  let sort_by_data cmp g =
    g |> A.sort (fun v1 v2 -> cmp v1.data v2.data)


  type ('a, 'b) update_t = 'a v_t -> iset_t -> 'a t -> 'b 

  let rec frontier (upd : ('a, bool) update_t)
    (fr : iset_t) (cls : iset_t) (g : 'a t) =

    let (fr_next, cls_next) =
      fr |> Ss.foldl (fun (fr_next, cls_cur) i ->
        let v = g.(i) in
        let opnb = Ss.diff v.nb cls_cur in
        let cl = upd v opnb g in
        (Ss.union fr_next opnb |> Ss.remove i,
          if cl then Ss.add i cls_cur else cls_cur)
      ) (Ss.empty, cls)
    in

    if Ss.is_empty fr then cls
    else frontier upd fr_next cls_next g


  let bfs (upd : ('a, unit) update_t) s g =
    frontier (fun v opnb g -> upd v opnb g; true)
      (Ss.sing s) Ss.empty g
     

  let steps_by (f : ('a, unit) update_t -> int -> 'a t -> iset_t) s g =
    f (fun v nb g -> nb |> Ss.iter (fun i -> setdi g i (getd g v + 1))) s g

end

module G = StaleGraph


let _ =
  let prim = 1000000007 in

  let n,m = rdi2 () in
  let es = rdvi2 m in
  let g = G.from_uedges n false es in
  G.setdi g 0 true;

  let rec decomp rvs ops cls =
    let v0 = Ss.choose ops in
    (* G.setdi g v0 true; *)
    (* puti v0; *)
    let opsr = ref (Ss.remove v0 ops) in
    let cls_next = g |> G.frontier (fun v opnb g ->
      opnb |> Ss.iter (fun w -> (* G.setdi g w true; *)
      (* puti w; *)
      opsr := Ss.remove w !opsr); true
      ) (Ss.sing v0) cls in
    (* print_list @@ Ss.to_list cls_next; *)
    (* print_list @@ Ss.to_list !opsr; *)
    if Ss.size cls_next = n then (Ss.add v0 rvs)
    else decomp (Ss.add v0 rvs) !opsr cls_next
  in

  let ops_init = Ss.of_list @@ L.range 1 `To n in
  let rvs = decomp Ss.empty ops_init Ss.empty in
  puti @@ Ss.size rvs - 1;
  ()
