#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>

#define MAXN 100
#define MAXM 100

using namespace std;

typedef long long ll;
typedef long double ld;

set<string> usernames;

string msgs[MAXM];
set<string> restrictions[MAXM];
bool expanded[MAXM];

int main() {
  int t; scanf("%d\n", &t);
  for(int tc = 1; tc <= t; tc++) {
    int n; scanf("%d\n", &n);

    usernames.clear();
    for(int i = 0; i < n; i++) {
      string user; cin >> user;
      usernames.insert(user);
    }

    int m; scanf("%d\n", &m);
    for(int i = 0; i < m; i++) {
      getline(cin, msgs[i]);

      int sep = msgs[i].find(':');
      string user = msgs[i].substr(0, sep);
      msgs[i] = msgs[i].substr(sep + 1);

      if(user != "?") {
        restrictions[i] = { user };
      }
      else {
        restrictions[i] = usernames;
        for(int prevIdx = -1; prevIdx < (int) msgs[i].size(); ) {
          int idx = msgs[i].find_first_of(".,!? ", ++prevIdx);
          if(idx == -1) idx = msgs[i].size();

          if(idx != prevIdx) {
            string word = msgs[i].substr(prevIdx, idx - prevIdx);
            if(usernames.count(word)) restrictions[i].erase(word);
          }
          prevIdx = idx;
        }
      }
    }

    memset(expanded, false, sizeof(expanded));

    bool stale = false, impossible = false;
    int expandedCount = 0;
    while(!stale && !impossible && expandedCount < m) {
      stale = true;

      for(int i = 0; i < m; i++) {
        if(!expanded[i] && restrictions[i].size() == 1) {
          if(i > 0) restrictions[i - 1].erase(*restrictions[i].begin());
          if(i < m - 1) restrictions[i + 1].erase(*restrictions[i].begin());
          expanded[i] = true;
          expandedCount++;
          stale = false;
        }
        if(restrictions[i].empty()) {
          impossible = true;
          break;
        }
      }
    }

    if(impossible || stale) printf("Impossible\n");
    else {
      for(int i = 0; i < m; i++) {
        printf("%s:%s\n", restrictions[i].begin()->c_str(), msgs[i].c_str());
      }
    }
  }
  return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <string>

#define MAXM 100

using namespace std;

int m;
set<string> usernames;

string msgs[MAXM];
set<string> restrictions[MAXM];
bool expanded[MAXM];

bool expand(int i) {
  if(!expanded[i] && restrictions[i].size() == 1) {
    expanded[i] = true;

    string user = *restrictions[i].begin();
    if(i > 0) {
      restrictions[i - 1].erase(user);
      if(!expand(i - 1)) return false;
    }
    if(i < m - 1) {
      restrictions[i + 1].erase(user);
      if(!expand(i + 1)) return false;
    }
  }
  return !restrictions[i].empty();
}

int main() {
  int t; scanf("%d\n", &t);
  for(int tc = 1; tc <= t; tc++) {
    int n; scanf("%d\n", &n);

    usernames.clear();
    for(int i = 0; i < n; i++) {
      string user; cin >> user;
      usernames.insert(user);
    }

    scanf("%d\n", &m);
    for(int i = 0; i < m; i++) {
      getline(cin, msgs[i]);

      int sep = msgs[i].find(':');
      string user = msgs[i].substr(0, sep);
      msgs[i] = msgs[i].substr(sep + 1);

      if(user != "?") {
        restrictions[i] = { user };
      }
      else {
        restrictions[i] = usernames;
        for(int prevIdx = -1; prevIdx < (int) msgs[i].size(); ) {
          int idx = msgs[i].find_first_of(".,!? ", ++prevIdx);
          if(idx == -1) idx = msgs[i].size();

          if(idx != prevIdx) {
            string word = msgs[i].substr(prevIdx, idx - prevIdx);
            if(usernames.count(word)) restrictions[i].erase(word);
          }
          prevIdx = idx;
        }
      }
    }

    memset(expanded, false, sizeof(expanded));
    bool impossible = false;
    for(int i = 0; i < m; i++) {
      if(!expand(i)) { impossible = true; break; }
    }

    if(impossible) printf("Impossible\n");
    else {
      for(int i = 0; i < m; i++) {
        string user = *restrictions[i].begin();
        if(i < m - 1) restrictions[i + 1].erase(user);
        printf("%s:%s\n", user.c_str(), msgs[i].c_str());
      }
    }
  }
  return 0;
}


#include <bits/stdc++.h>
#define ll long long

using namespace std;
#define N 101

vector <string> caras;
char temp[1000];
set <string> pode[N];
vector <string> entrada;

void get (int idx){
    pode[idx].clear();
    scanf (" %[^\n]s", temp);
    entrada.push_back (temp);
    string s = temp;
    for (auto s: caras) pode[idx].insert(s);
    if (s[0] == '?'){
        for (int j = 0; j < caras.size(); j++){
            for (int i = 0; i < s.size(); i++){
                int k = 0;
                while (k < caras[j].size() && caras[j][k] == s[i + k]) k++;
                if (i - 1 >= 0 && isalnum(s[i-1])) continue;
                if (isalnum(s[i+k])) continue;

                if (k == caras[j].size()){
                    pode[idx].erase(caras[j]);
                    break;
                }
            }
        }
    } else{
        int k = 0;
        pode[idx].clear();
        string nome;
        while (s[k] != ':') nome += s[k++];
        pode[idx].insert(nome);
    }
}

map <pair<int, string>, bool> dp;
int maximo;
vector <string> ans;

bool solve (int i, string s){
    if (dp.count({i, s})) return dp[{i, s}];
    auto &ret = dp[{i, s}] = false;
    if (i == maximo) return ret = true;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        ret |= solve(i + 1, s2);
        if (ret) return ret;
    }
    return ret;
}

void build (int i, string s){
    if (i == maximo) return;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        if (dp[{i+1, s2}]){
            ans.push_back(s2);
            build(i+1, s2);
            return;
        }
    }
}

int main(){
    int t;
    scanf ("%d", &t);
    while (t--){
        dp.clear();
        entrada.clear();
        ans.clear();
        int n;
        scanf ("%d", &n);
        caras.clear();
        for (int i = 0; i < n; i++){
            scanf ("%s", temp);
            caras.push_back (temp);
        }
        int m;
        scanf ("%d", &m);
        maximo = m;
        for (int i = 0; i < m; i++){
            get(i);
        }
        solve(0, "");
        if (dp[{0, ""}]){
            build(0, "");
            int k = 0;
            for (auto s: entrada){
                if (s[0] == '?')
                    s.erase(s.begin()), printf ("%s", ans[k].c_str());
                printf ("%s\n", s.c_str());
                k++;
            }

        } else {
            printf ("Impossible\n");
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define ll long long

using namespace std;
#define N 101

vector <string> caras;
char temp[1000];
set <string> pode[N];
vector <string> entrada;

void get (int idx){
    pode[idx].clear();
    scanf (" %[^\n]s", temp);
    entrada.push_back (temp);
    string s = temp;
    for (auto s: caras) pode[idx].insert(s);
    if (s[0] == '?'){
        for (int j = 0; j < caras.size(); j++){
            for (int i = 0; i < s.size(); i++){
                int k = 0;
                while (k < caras[j].size() && caras[j][k] == s[i + k]) k++;
                if (i - 1 >= 0 && isalnum(s[i-1])) continue;
                if (isalnum(s[i+k])) continue;

                if (k == caras[j].size()){
                    pode[idx].erase(caras[j]);
                    break;
                }
            }
        }
    } else{
        int k = 0;
        pode[idx].clear();
        string nome;
        while (s[k] != ':') nome += s[k++];
        pode[idx].insert(nome);
    }
}

map <pair<int, string>, bool> dp;
int maximo;
vector <string> ans;

bool solve (int i, string s){
    if (dp.count({i, s})) return dp[{i, s}];
    auto &ret = dp[{i, s}] = false;
    if (i == maximo) return ret = true;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        ret |= solve(i + 1, s2);
    }
    return ret;
}

void build (int i, string s){
    if (i == maximo) return;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        if (dp[{i+1, s2}]){
            ans.push_back(s2);
            build(i+1, s2);
            return;
        }
    }
}

int main(){
    int t;
    scanf ("%d", &t);
    while (t--){
        dp.clear();
        entrada.clear();
        ans.clear();
        int n;
        scanf ("%d", &n);
        caras.clear();
        for (int i = 0; i < n; i++){
            scanf ("%s", temp);
            caras.push_back (temp);
        }
        int m;
        scanf ("%d", &m);
        maximo = m;
        for (int i = 0; i < m; i++){
            get(i);
        }
        solve(0, "");
        if (dp[{0, ""}]){
            build(0, "");
            int k = 0;
            for (auto s: entrada){
                if (s[0] == '?')
                    s.erase(s.begin()), printf ("%s", ans[k].c_str());
                printf ("%s\n", s.c_str());
                k++;
            }

        } else {
            printf ("Impossible\n");
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define ll long long

using namespace std;
#define N 101

vector <string> caras;
char temp[1000];
set <string> pode[N];
vector <string> entrada;

void get (int idx){
    pode[idx].clear();
    scanf (" %[^\n]s", temp);
    entrada.push_back (temp);
    string s = temp;
    for (auto s: caras) pode[idx].insert(s);
    if (s[0] == '?'){
        for (int i = 0; i < s.size(); i++){
            for (int j = 0; j < caras.size(); j++){
                int k = 0;
                while (k < caras[j].size() && caras[j][k] == s[i + k]) k++;
                if (i - 1 >= 0 && isalnum(s[i-1])) continue;
                if (isalnum(s[i+k])) continue;

                if (k == caras[j].size())
                    pode[idx].erase(caras[j]);
            }
        }
    } else{
        int k = 0;
        pode[idx].clear();
        string nome;
        while (s[k] != ':') nome += s[k++];
        pode[idx].insert(nome);
    }
}

map <pair<int, string>, bool> dp;
int maximo;
vector <string> ans;

bool solve (int i, string s){
    if (dp.count({i, s})) return dp[{i, s}];
    auto &ret = dp[{i, s}] = false;
    if (i == maximo) return ret = true;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        ret |= solve(i + 1, s2);
    }
    return ret;
}

void build (int i, string s){
    if (i == maximo) return;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        if (dp[{i+1, s2}]){
            ans.push_back(s2);
            build(i+1, s2);
            return;
        }
    }
}

int main(){
    int t;
    scanf ("%d", &t);
    while (t--){
        dp.clear();
        entrada.clear();
        ans.clear();
        int n;
        scanf ("%d", &n);
        caras.clear();
        for (int i = 0; i < n; i++){
            scanf ("%s", temp);
            caras.push_back (temp);
        }
        int m;
        scanf ("%d", &m);
        maximo = m;
        for (int i = 0; i < m; i++){
            get(i);
        }
        solve(0, "");
        if (dp[{0, ""}]){
            build(0, "");
            int k = 0;
            for (auto s: entrada){
                if (s[0] == '?')
                    s.erase(s.begin()), printf ("%s", ans[k].c_str());
                printf ("%s\n", s.c_str());
                k++;
            }

        } else {
            printf ("Impossible\n");
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define ll long long

using namespace std;
#define N 101

vector <string> caras;
char temp[1000];
set <string> pode[N];
vector <string> entrada;

void get (int idx){
    pode[idx].clear();
    scanf (" %[^\n]s", temp);
    entrada.push_back (temp);
    string s = temp;
    for (auto s: caras) pode[idx].insert(s);
    if (s[0] == '?'){
        for (int i = 0; i < s.size(); i++){
            for (int j = 0; j < caras.size(); j++){
                int k = 0;
                while (k < caras[j].size() && caras[j][k] == s[i + k]) k++;
                if (i - 1 >= 0 && isalnum(s[i-1])) continue;
                if (isalnum(s[i+k])) continue;

                if (k == caras[j].size())
                    pode[idx].erase(caras[j]);
            }
        }
    } else{
        int k = 0;
        pode[idx].clear();
        string nome;
        while (s[k] != ':') nome += s[k++];
        pode[idx].insert(nome);
    }
}

map <pair<int, string>, bool> dp;
int maximo;
vector <string> ans;

bool solve (int i, string s){
    if (dp.count({i, s})) return dp[{i, s}];
    auto &ret = dp[{i, s}] = false;
    if (i == maximo) return ret = true;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        ret |= solve(i + 1, s2);
    }
    return ret;
}

void build (int i, string s){
    if (i == maximo) return;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        if (dp[{i+1, s2}]){
            ans.push_back(s2);
            build(i+1, s2);
            return;
        }
    }
}

int main(){
    int t;
    scanf ("%d", &t);
    while (t--){
        dp.clear();
        entrada.clear();
        ans.clear();
        int n;
        scanf ("%d", &n);
        caras.clear();
        for (int i = 0; i < n; i++){
            scanf ("%s", temp);
            caras.push_back (temp);
        }
        int m;
        scanf ("%d", &m);
        maximo = m;
        for (int i = 0; i < m; i++){
            get(i);
        }
        solve(0, "");
        if (dp[{0, ""}]){
            build(0, "");
            int k = 0;
            for (auto s: entrada){
                if (s[0] == '?')
                    s.erase(s.begin()), cout << ans[k];
                cout << s << endl;
                k++;
            }

        } else {
            cout << "Impossible" << endl;
        }
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long

using namespace std;
#define N 101

vector <string> caras;
char temp[1000];
set <string> pode[N];
vector <string> entrada;

void get (int idx){
    pode[idx].clear();
    scanf (" %[^\n]s", temp);
    entrada.push_back (temp);
    string s = temp;
    for (auto s: caras) pode[idx].insert(s);
    if (s[0] == '?'){
        for (int i = 0; i < s.size(); i++){
            for (int j = 0; j < caras.size(); j++){
                int k = 0;
                while (k < caras[j].size() && caras[j][k] == s[i + k]) k++;
                if (i - 1 >= 0 && isalnum(s[i-1])) continue;
                if (isalnum(s[i+k])) continue;

                if (k == caras[j].size())
                    pode[idx].erase(caras[j]);
            }
        }
    } else{
        int k = 0;
        pode[idx].clear();
        string nome;
        while (s[k] != ':') nome += s[k++];
        pode[idx].insert(nome);
    }
}

map <pair<int, string>, bool> dp;
int maximo;
vector <string> ans;

bool solve (int i, string s){
    if (dp.count({i, s})) return dp[{i, s}];
    auto &ret = dp[{i, s}] = false;
    if (i == maximo) return ret = true;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        ret |= solve(i + 1, s2);
        if (ret) return ret;
    }
    return ret;
}

void build (int i, string s){
    if (i == maximo) return;
    for (auto s2: pode[i]){
        if (s == s2) continue;
        if (dp[{i+1, s2}]){
            ans.push_back(s2);
            build(i+1, s2);
            return;
        }
    }
}

int main(){
    int t;
    scanf ("%d", &t);
    while (t--){
        dp.clear();
        entrada.clear();
        ans.clear();
        int n;
        scanf ("%d", &n);
        caras.clear();
        for (int i = 0; i < n; i++){
            scanf ("%s", temp);
            caras.push_back (temp);
        }
        int m;
        scanf ("%d", &m);
        maximo = m;
        for (int i = 0; i < m; i++){
            get(i);
        }
        solve(0, "");
        if (dp[{0, ""}]){
            build(0, "");
            int k = 0;
            for (auto s: entrada){
                if (s[0] == '?')
                    s.erase(s.begin()), cout << ans[k];
                cout << s << endl;
                k++;
            }

        } else {
            cout << "Impossible" << endl;
        }
    }

    return 0;
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		string curr;
		getline(cin, curr);
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			getline(cin, curr);
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':') speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < curr.size()) {
				if(curr[j] == '.' or curr[j] == ',' or curr[j] == '!'
					or curr[j] == '?' or curr[j] == ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				else if(speaker != "?" and speaker != users[j]) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int cU = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				cU = j;
				break;
			}
		}
		result[m - 1] = users[cU] + messages[m - 1];
		if(cU == -1) {
			cout << "Impossible" << endl;
		}
		else {
			for(int i = m - 2; i >= 0; i--) {
				cU = memo[i + 1][cU];
				result[i] = users[cU] + messages[i];
			}
			for(int i = 0; i < m; i++)
				cout << result[i] << endl;
		}
	}
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		string curr;
		getline(cin, curr);
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			getline(cin, curr);
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':' and j < curr.size()) speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < curr.size()) {
				if(curr[j] == '.' or curr[j] == ',' or curr[j] == '!'
					or curr[j] == '?' or curr[j] == ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				else if(speaker != "?" and speaker != users[j]) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int cU = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				cU = j;
				break;
			}
		}
		result[m - 1] = users[cU] + messages[m - 1];
		if(cU == -1) {
			cout << "Impossible" << endl;
		}
		else {
			for(int i = m - 2; i >= 0; i--) {
				cU = memo[i + 1][cU];
				result[i] = users[cU] + messages[i];
			}
			for(int i = 0; i < m; i++)
				cout << result[i] << endl;
			continue;
		}
	}
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		string curr;
		getline(cin, curr);
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			getline(cin, curr);
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':') speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < curr.size()) {
				if(curr[j] == '.' or curr[j] == ',' or curr[j] == '!'
					or curr[j] == '?' or curr[j] == ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				else if(speaker != "?" and speaker != users[j]) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int cU = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				cU = j;
				break;
			}
		}
		result[m - 1] = users[cU] + messages[m - 1];
		if(cU == -1) {
			cout << "Impossible" << endl;
			continue;
		}
		for(int i = m - 2; i >= 0; i--) {
			cU = memo[i + 1][cU];
			result[i] = users[cU] + messages[i];
		}
		for(int i = 0; i < m; i++)
			cout << result[i] << endl;
	}
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			string curr;
			cin >> curr;
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':') speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < n) {
				if(curr[j] != '.' and curr[j] != ',' and curr[j] != '!'
					and curr[j] != '?' and curr[j] != ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int curr = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				curr = j;
				break;
			}
			result.push_back(users[curr] + messages[m - 1]);
		}
		if(curr == -1) {
			cout << "Impossible" << endl;
			continue;
		}
		for(int i = m - 2; i >= 0; i--) {
			curr = memo[i + 1][curr];
			result.push_back(users[curr] + messages[i]);
		}
		for(int i = 0; i < m; i++)
			cout << result[i] << endl;
	}
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	for(int T = 0; T < t; T++) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		string curr;
		getline(cin, curr);
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			getline(cin, curr);
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':' and j < curr.size()) speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < curr.size()) {
				if(curr[j] == '.' or curr[j] == ',' or curr[j] == '!'
					or curr[j] == '?' or curr[j] == ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				else if(speaker != "?" and speaker != users[j]) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int cU = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				cU = j;
				break;
			}
		}
		result[m - 1] = users[cU] + messages[m - 1];
		if(cU == -1) {
			cout << "Impossible" << endl;
		}
		else {
			for(int i = m - 2; i >= 0; i--) {
				cU = memo[i + 1][cU];
				result[i] = users[cU] + messages[i];
			}
			for(int i = 0; i < m; i++)
				cout << result[i] << endl;
		}
	}
}


#include <iostream>
#include <string>
#include <set>
#include <vector>

using namespace std;

int main() {
	int t;
	cin >> t;
	for(int T = 0; T < t; T++) {
		int n, m;
		cin >> n;
		vector<string> users(n);
		for(int i = 0; i < n; i++)
			cin >> users[i];
		cin >> m;
		string curr;
		vector<string> messages(m);
		vector<vector<int>> memo(m, vector<int> (n, -1));
		for(int i = 0; i < m; i++) {
			getline(cin, curr);
			if(curr.empty())
				getline(cin, curr);
			string speaker;
			set<string> other;
			int j = 0;
			while(curr[j] != ':') speaker += curr[j++];
			messages[i] = curr.substr(speaker.size());
			string temp;
			while(++j < curr.size()) {
				if(curr[j] == '.' or curr[j] == ',' or curr[j] == '!'
					or curr[j] == '?' or curr[j] == ' ') {
					other.insert(temp);
					temp.clear();
				}
				else
					temp += curr[j];
			}
			other.insert(temp);
			for(int j = 0; j < n; j++) {
				if(speaker == "?" and other.count(users[j])) continue;
				else if(speaker != "?" and speaker != users[j]) continue;
				if(i == 0) {
					memo[i][j] = j;
					continue;
				}
				for(int k = 0; k < n; k++) {
					if(k != j and memo[i - 1][k] != -1) {
						memo[i][j] = k;
						break;
					}
				}
			}
		}
		vector<string> result(m);
		int cU = -1;
		for(int j = 0; j < n; j++) {
			if(memo[m - 1][j] != -1) {
				cU = j;
				break;
			}
		}
		if(cU == -1) {
			cout << "Impossible" << endl;
		}
		else {
			result[m - 1] = users[cU] + messages[m - 1];
			for(int i = m - 2; i >= 0; i--) {
				cU = memo[i + 1][cU];
				result[i] = users[cU] + messages[i];
			}
			for(int i = 0; i < m; i++)
				cout << result[i] << endl;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cin.tie(0);ios::sync_with_stdio(false);
//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));
    vector<bool> cned(n, false);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }
    rep(i, 0, n) sort(all(e[i]));

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        if (cned[i])
            continue;

        int ind = i + 1;
        sort(all(e[i]));

        if (siz(e[i]) == 0)
        {
            rep(j, ind, n)
            {
                u.connect(i, j);
                cout << i << " " << ind << endl; //
            }
        }
        else
        {
            rep(j, lb(all(e[i]), ind) - e[i].begin(), siz(e[i]))
            {
                while (ind < e[i][j])
                {
                    u.connect(i, ind);
                    //cout << i << " " << ind << endl;
                    cned[ind] = true;
                    ind++;
                }
                ind++;
            }
            while (ind < n)
            {
                u.connect(i, ind);
                //cout << i << " " << ind << endl;
                cned[ind] = true;
                ind++;
            }
        }
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m;
    cin >> n >> m;
    set<P> e;
    set<int> to;rep(i,0,n)to.insert(i);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e.insert({a,b});
        e.insert({b,a});
    }

    UnionFind<int> u(n);
    queue<int> q;

    rep(i, 0, n)
    {
        if(!to.count(i))continue;

        q.push(i);
        to.erase(i);

        while(!q.empty()){
            int now=q.front();
            q.pop();

            if(to.empty())goto flag;

            for(auto itr=to.begin();itr!=to.end();itr++){
                if(!e.count({now,*itr})){
                    u.connect(now,*itr);
                    q.push(*itr);
                    to.erase(itr);
                }
            }
        }
    }

    flag:;
    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cin.tie(0);ios::sync_with_stdio(false);
//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));
    vector<bool> cned(n, false);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        if (cned[i])
            continue;

        int ind = i + 1;
        sort(all(e[i]));

        rep(j, lb(all(e[i]), ind) - e[i].begin(), siz(e[i]))
        {
            while (ind < e[i][j])
            {
                u.connect(i, ind);
                //cout << i << " " << ind << endl;
                cned[ind] = true;
                ind++;
            }
            ind++;
        }
        while (ind < n)
        {
            u.connect(i, ind);
            //cout << i << " " << ind << endl;
            cned[ind] = true;
            ind++;
        }
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m,ans=0;
    cin >> n >> m;
    set<P> e;
    set<int> to;rep(i,0,n)to.insert(i);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e.insert({a,b});
        e.insert({b,a});
    }

    queue<int> q;

    rep(i, 0, n)
    {
        if(!to.count(i))continue;

        q.push(i);
        to.erase(i);

        while(!q.empty()){
            int now=q.front();
            q.pop();

            for(int itr:to){
                if(!e.count({now,itr})){
                    q.push(itr);
                    to.erase(itr);
                }
            }
        }
        ans++;
    }

    cout << ans - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m,ans=0;
    cin >> n >> m;
    set<P> e;
    set<int> to;rep(i,0,n)to.insert(i);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e.insert({a,b});
        e.insert({b,a});
    }

    queue<int> q;

    rep(i, 0, n)
    {
        if(!to.count(i))continue;

        q.push(i);
        to.erase(i);

        while(!q.empty()){
            int now=q.front();
            q.pop();

            for(auto itr=to.begin();itr!=to.end();){
                if(!e.count({now,*itr})){
                    q.push(*itr);
                    itr=to.erase(itr);
                }else{
                    itr++;
                }
            }
        }
        ans++;
    }

    cout << ans - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));
    vector<bool> cned(n, false);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        if (cned[i])
            continue;

        int ind = 0;
        sort(all(e[i]));

        rep(j, 0, siz(e[i]))
        {
            while (ind < e[i][j])
            {
                u.connect(i, ind);
                //cout << i << " " << ind << endl;
                cned[ind] = true;
                ind++;
            }
            ind++;
        }
        while (ind < n)
        {
            u.connect(i, ind);
            //cout << i << " " << ind << endl;
            cned[ind] = true;
            ind++;
        }
        if(u.size(0)==n)break;
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));
    vector<bool> cned(n, false);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        if (cned[i])
            continue;

        int ind = i + 1;
        sort(all(e[i]));

        rep(j, 0, siz(e[i]))
        {
            while (ind < e[i][j])
            {
                u.connect(i, ind);
                //cout << i << " " << ind << endl;
                cned[ind] = true;
                ind++;
            }
            ind++;
        }
        while (ind < n)
        {
            u.connect(i, ind);
            //cout << i << " " << ind << endl;
            cned[ind] = true;
            ind++;
        }
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m,ans=0;
    cin >> n >> m;
    set<P> e;
    set<int> to;rep(i,0,n)to.insert(i);

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e.insert({a,b});
        e.insert({b,a});
    }

    queue<int> q;

    rep(i, 0, n)
    {
        if(!to.count(i))continue;

        q.push(i);
        to.erase(i);

        while(!q.empty()){
            int now=q.front();
            q.pop();

            //if(to.empty())goto flag;

            for(auto itr=to.begin();itr!=to.end();){
                if(!e.count({now,*itr})){
                    q.push(*itr);
                    itr=to.erase(itr);
                }else{
                    itr++;
                }
            }
        }
        ans++;
    }

    flag:;

    cout << ans - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        int ind = 0;
        sort(all(e[i]));

        rep(j, 0, siz(e[i]))
        {
            while (ind < e[i][j])
            {
               if(u.same(i,ind)){
                  ind++;
                  continue;
               }
                u.connect(i, ind);
                ind++;
            }
            ind++;
        }
        while (ind < n)
        {
            u.connect(i, ind);
            //cout << i << " " << ind << endl;
            ind++;
        }
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T, typename U>
void chmin(T &t, const U &u)
{
    if (t > u)
        t = u;
}
template <typename T, typename U>
void chmax(T &t, const U &u)
{
    if (t < u)
        t = u;
}
template <typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T>
T mpow(T a, T n)
{
    T res = 1;
    for (; n; n >>= 1)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
    }
    return res;
}

//cout<<fixed<<setprecision(20);

template <typename T>
class UnionFind
{
public:
    //以下公開

    //親の番号を格納する。親である場合は-(その集合のサイズ)
    vector<T> Parent;

    //作るときはParentの値を全て-1にする
    //こうすると全てバラバラになる
    UnionFind(T N)
    {
        Parent = vector<T>(N, -1);
    }

    //Aがどのグループに属しているか調べる
    T root(T A)
    {
        if (Parent[A] < 0)
            return A;
        return Parent[A] = root(Parent[A]);
    } //代入しておくことで参照を速くする

    //自分のいるグループの頂点数を調べる
    T size(T A)
    {
        return -Parent[root(A)];
    } //親である場合は-(その集合のサイズ)なので、Ａの親の

    //AとBをくっ付ける
    bool connect(T A, T B)
    {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B)
        {
            //すでにくっついてるからくっ付けない
            return false;
        }

        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらひっくり返しちゃう。
        if (size(A) < size(B))
            swap(A, B);

        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;

        return true;
    }

    bool same(T A, T B)
    {
        return root(A) == root(B);
    }
};

signed main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    ll n, m;
    cin >> n >> m;
    vector<vector<ll>> e(n, vector<ll>(0));

    rep(i, 0, m)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        e[a].pb(b);
        e[b].pb(a);
    }

    UnionFind<int> u(n);

    rep(i, 0, n)
    {
        int ind = 0;
        sort(all(e[i]));

        rep(j, 0, siz(e[i]))
        {
            while (ind < e[i][j])
            {
                u.connect(i, ind);
                ind++;
            }
            ind++;
        }
        while (ind < n)
        {
            u.connect(i, ind);
            ind++;
        }
        if(u.size(0)==n)break;
    }

    set<int> se;
    rep(i, 0, n)
    {
        if (!se.count(u.root(i)))
            se.insert(u.root(i));
    }

    cout << siz(se) - 1 << endl;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(g[i].size() == 0)continue;
        int cnt;
        if(take[i] == 0)cnt=1;
        else cnt = 0;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
       // cout << " j = " << j <<" " << g[i].size() << " " << g[i][j] <<" -> ";
        g[i].push_back(-1);
        int sz = g[i].size();
        for(int k = i + 1 ; !(n - k == sz - j && k == g[i][j]) && j < sz && k <= n;k++){
            //cout << k <<"  " << j << endl;
            if(g[i][j] == k){
                j++;
                continue;
            }
           // cout << k << " " << j  << " " << g[i][j]<< " nxt ";
            if(take[k] != 0)cnt=0;
            take[k] = i;
        }
        //cout << cnt << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];
vector<pair<int, int> > v;

void dfs(int node) {
    used[node] = 1;
    sort(g[node].begin(), g[node].end());
    g[node].push_back(-1);
    for (int i = 1, j = 0; i <= n; i++) {
        if (i == node)continue;
        else if (i == g[node][j]) {
            j++;
        } else {
            if (used[i])continue;
            //cout << node << " " << i << endl;
            dfs(i);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int x = 0; x < v.size(); x++) {
        int i = v[x].second;
        if (used[i])continue;
        if (g[i].size() == n - 1) {
            ans++;
            continue;
        }
        dfs(i);
        ans++;
        // cout << i << endl;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N], cnt = 1;
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int k = 0, i; k < v.size(); k++) {
        i = v[k].second;
        int add = 0;
        if(take[i] == 0)add = 1;
        sort(g[i].begin(),g[i].end());
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
        g[i].push_back(-1);
        int sz = g[i].size();
        for(int k = i + 1 ; !(n - k - 1 == sz - j && k == g[i][j]) && k <= n;k++){
            if(g[i][j] == k){
                j++;
                continue;
            }
            if(take[k] != 0)add=0;
            else cnt++;
            take[k] = i;
            if(cnt == n){
                cout << 0;
                return 0;
            }
        }
        ans += add;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        v.push_back({a, b});
    }
    sort(v.begin(), v.end());
    for (int i = 0; i < m; i++) {
        g[v[i].first].push_back(v[i].second);
        g[v[i].second].push_back(v[i].first);
    }
    for (int i = 1; i <= n; i++) {
        if(take[i] == 1 || g[i].size() == 0)continue;
        int cnt = 1;
        for(int j = 0, k = 1 ; j < g[i].size();k++){
            if(g[i][j] == k){
                j++;
                continue;
            }
            if(take[g[i][j]] == 1)cnt=0;
            take[g[i][j]] = 1;
        }
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N], cnt = 1;
vector<int> g[N];

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(g[i].size() == 0)continue;
        int add;
        if(take[i] == 0)add=1;
        else add = 0;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
       // cout << " j = " << j <<" " << g[i].size() << " " << g[i][j] <<" -> ";
        g[i].push_back(-1);
        int sz = g[i].size();
        for(int k = i + 1 ; !(n - k == sz - j && k == g[i][j]) && j < sz && k <= n;k++){
            //cout << k <<"  " << j << endl;
            if(g[i][j] == k){
                j++;
                continue;
            }
           // cout << k << " " << j  << " " << g[i][j]<< " nxt ";
            if(take[k] != 0)add=0;
            else cnt++;
            take[k] = i;
            if(cnt == n){
                cout << 0;
                return 0;
            }
        }
        //cout << add << endl;
        ans += add;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, cnt, dist[N];
vector<int> g[N], v;
set<int> nodes;
queue<int> q;

void bfs(int node) {
    q.push(node);
    while(!q.empty()){
        int cur = q.front();
        q.pop();
        for(auto x : nodes){
            if(binary_search(g[cur].begin(),g[cur].end(),x) == false && x != cur){
                v.push_back(x);
                q.push(x);
            }
        }
        for(int i=0;i<v.size();i++)
            nodes.erase(v[i]);
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 0, a, b; i < m; i++) {
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        sort(g[i].begin(), g[i].end());
        nodes.insert(i);
    }
    while (!nodes.empty()) {
        int node = *nodes.begin();
        nodes.erase(node);
        bfs(node);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;
set<int> st;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    st.insert(1);
    for (int i = 1; i <= n; i++) {
        if(g[i].size() == 0)continue;
        int cnt;
        if(take[i] == 0)cnt=1;
        else cnt = 0;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
       // cout << " j = " << j <<" " << g[i].size() << " " << g[i][j] <<" -> ";
        g[i].push_back(-1);
        int sz = g[i].size();
        for(int k = i + 1 ; !(n - k == sz - j && k == g[i][j]) && j < sz && k <= n;k++){
            //cout << k <<"  " << j << endl;
            if(g[i][j] == k){
                j++;
                continue;
            }
           // cout << k << " " << j  << " " << g[i][j]<< " nxt ";
            if(take[k] != 0)cnt=0;
            take[k] = i;
            st.insert(i);
            if(st.size() == n){
                cout << 0;
                return 0;
            }
        }
        //cout << cnt << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];
vector<pair<int, int> > v;

void dfs(int node){
    used[node] = 1;
    sort(g[node].begin(), g[node].end());
    g[node].push_back(-1);
    for(int i=1,j=0;i<=n;i++){
        if(i == node)continue;
        else if(i == g[node][j]){
            j++;
        }else{
            if(used[i])continue;
            //cout << node << " " << i << endl;
            dfs(i);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        dist[i] = i;
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int x = 0; x < v.size(); x++) {
        int i = v[x].second;
        if(used[i])continue;
        dfs(i);
        ans++;
       // cout << i << endl;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, cnt, dist[N];
vector<int> g[N], v;
set<int> nodes;
queue<int> q;

void dfs(int node) {
    q.push(node);
    while(!q.empty()){
        int cur = q.front();
        q.pop();
        for(auto x : nodes){
            if(binary_search(g[cur].begin(),g[cur].end(),x) == false && x != cur){
                v.push_back(x);
                q.push(x);
            }
        }
        for(int i=0;i<v.size();i++)
            nodes.erase(v[i]);
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        sort(g[i].begin(), g[i].end());
        nodes.insert(i);
    }
    while (!nodes.empty()) {
        int node = *nodes.begin();
        nodes.erase(node);
        dfs(node);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];
vector<pair<int, int> > v;

void dfs(int node) {
    used[node] = 1;
    if (g[node].size() == 0){
        cout << 0 << endl;
        exit(0);
    }
    sort(g[node].begin(), g[node].end());
    int j = lower_bound(g[node].begin(), g[node].end(), node + 1) - g[node].begin();
    g[node].push_back(-1);
    for (int i = node + 1; /*!(n - i == g[node].size() - j && i == g[node][j]) && */i <= n; i++) {
        if (i == g[node][j]) {
            j++;
        } else {
            if (used[i])continue;
            dfs(i);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        if (used[i])continue;
        if (g[i].size() == n - 1){
            ans++;
            continue;
        }
        dfs(i);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(take[i] == 1 || g[i].size() == 0)continue;
        int cnt = 1;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        g[i].push_back(-1);
        for(int j = 0, k = 1 ; j < g[i].size() && k <= n;k++){
            if(i == k)continue;
            if(g[i][j] == k){
                j++;
                continue;
            }
          //  cout << k << " ";
            if(take[k] == 1)cnt=0;
            take[k] = 1;
        }
        //cout << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N], cnt = 1;
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int x = 0; x < v.size(); x++) {
        int i = v[x].second;
        int add = 0;
        if (take[i] == 0)add = 1, take[i] = i;
        sort(g[i].begin(), g[i].end());
        g[i].push_back(-1);
        int sz = g[i].size();
        for (int k = 1, j = 0; k <= n; k++) {
            if (k == i)continue;
            if (g[i][j] == k) {
                j++;
                continue;
            }
            if (take[k] != 0)add = 0;
            else cnt++;
            take[k] = take[i];
            if (cnt == n) {
                cout << 0;
                return 0;
            }
        }
        ans += add;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N], v;

void dfs(int node) {
    used[node] = 1;
    for(int i=node + 1;i<=n;i++){
        if(used[i])continue;
        if(binary_search(g[node].begin(),g[node].end(),i) == false)
            dfs(i);
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i=1;i<=n;i++)
        sort(g[i].begin(),g[i].end());
    for (int i = 1; i <= n; i++) {
        if(used[i])continue;
        dfs(i);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];
vector<pair<int, int> > v;

void dfs(int node) {
    used[node] = 1;
    sort(g[node].begin(), g[node].end());
    g[node].push_back(-1);
    for (int i = 1, j = 0; i <= n; i++) {
        if (i == node)continue;
        else if (i == g[node][j]) {
            j++;
        } else {
            if (used[i])continue;
            //cout << node << " " << i << endl;
            dfs(i);
        }
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 0, a, b; i < m; i++) {
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int x = 0; x < v.size(); x++) {
        int i = v[x].second;
        if (used[i])continue;
        if (g[i].size() == n - 1) {
            ans++;
            continue;
        }
        dfs(i);
        ans++;
        // cout << i << endl;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N], v;

void dfs(int node) {
    used[node] = 1;
    for(int i=node + 1;i<=n;i++){
        if(used[i])continue;
        if(binary_search(g[node].begin(),g[node].end(),i) == false){
            dfs(i);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i=1;i<=n;i++){
        if(g[i].size() == 0)return cout << 0,0;
        sort(g[i].begin(),g[i].end());
    }
    for (int i = 1; i <= n; i++) {
        if(used[i])continue;
        dfs(i);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(take[i] == 1 || g[i].size() == 0)continue;
        int cnt = 1;
        sort(g[i].begin(),g[i].end());
        for(int j = 0, k = 1 ; j < g[i].size();k++){
            if(g[i][j] == k || i == k){
                j++;
                continue;
            }
            if(take[g[i][j]] == 1)cnt=0;
            take[g[i][j]] = 1;
        }
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(take[i] != 0 || g[i].size() == 0)continue;
        int cnt = 1;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        g[i].push_back(-1);
        for(int j = 0, k = 1 ; j < g[i].size() && k <= n;k++){
            if(i == k)continue;
            if(g[i][j] == k){
                j++;
                continue;
            }
          //  cout << k << " ";
            if(take[k] != 0)cnt=0;
            take[k] = i;
        }
        //cout << endl;
        ans += cnt;
    }
    for(int i=1;i<=n;i++){
        if(take[i] == 0 || g[i].size() == 0)continue;
        int cnt = 0;
        //cout << i << " -> ";
        for(int j = 0, k = 1 ; j < g[i].size() && k <= n;k++){
            if(i == k)continue;
            if(g[i][j] == k){
                j++;
                continue;
            }
            //cout << k << " ";
            if(take[k] != take[i] && take[i] != k)cnt=-1;
        }
        //cout << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N], cnt;
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        v.push_back({g[i].size(), i});
    }
    sort(v.begin(), v.end());
    for (int x = 0; x < v.size(); x++) {
        int i = v[x].second;
        int add = 0;
        if (take[i] == 0){
            add = 1;
            take[i] = i;
            cnt++;
        }
        sort(g[i].begin(), g[i].end());
        g[i].push_back(-1);
        int sz = g[i].size();
        for (int k = 1, j = 0; k <= n; k++) {
            if (k == i)continue;
            if (g[i][j] == k) {
                j++;
                continue;
            }
            if (take[k] != 0)add = 0;
            else cnt++;
            take[k] = take[i];
            if (cnt == n) {
                cout << max(0,ans-1);
                return 0;
            }
        }
        ans += add;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];
vector<pair<int, int> > v;

void dfs(int node) {
    used[node] = 1;
    if (g[node].size() == 0){
        cout << 0 << endl;
        exit(0);
    }
    sort(g[node].begin(), g[node].end());
    int j = lower_bound(g[node].begin(), g[node].end(), node + 1) - g[node].begin();
    g[node].push_back(-1);
    for (int i = node + 1; !(n - i == g[node].size() - j && i == g[node][j]) && i <= n; i++) {
        if (i == g[node][j]) {
            j++;
        } else {
            if (used[i])continue;
            dfs(i);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if (g[i].size() == 0)return cout << 0, 0;
        if (used[i])continue;
        if (g[i].size() == n - 1){
            ans++;
            continue;
        }
        dfs(i);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(take[i] != 0 || g[i].size() == 0)continue;
        int cnt = 1;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        g[i].push_back(-1);
        for(int j = 0, k = 1 ; j < g[i].size() && k <= n;k++){
            if(i == k)continue;
            if(g[i][j] == k){
                j++;
                continue;
            }
          //  cout << k << " ";
            if(take[k] != 0)cnt=0;
            take[k] = i;
        }
        //cout << endl;
        ans += cnt;
    }
    for(int i=1;i<=n;i++){
        if(take[i] == 0 || g[i].size() == 0)continue;
        int cnt = 0;
        sort(g[i].begin(),g[i].end());
        //cout << i << " -> ";
        for(int j = 0, k = 1 ; j < g[i].size() && k <= n;k++){
            if(i == k)continue;
            if(g[i][j] == k){
                j++;
                continue;
            }
            //cout << k << " ";
            if(take[k] != take[i] && take[i] != k)cnt=-1;
        }
        //cout << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N];
vector<int> g[N];
vector<pair<int, int> > v;

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(g[i].size() == 0)continue;
        int cnt;
        if(take[i] == 0)cnt=1;
        else cnt = 0;
        sort(g[i].begin(),g[i].end());
       // cout << i << " -> ";
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
       // cout << " j = " << j <<" " << g[i][j] <<" -> ";
        //if(g[i].size() - j == n - i + 1 || j == g[i].size())continue;
        g[i].push_back(-1);
        for(int k = i + 1 ; j < g[i].size() && k <= n;k++){
            if(g[i][j] == k){
                j++;
                continue;
            }
           // cout << k << " ";
            if(take[k] != 0)cnt=0;
            take[k] = i;
        }
        //cout << cnt << endl;
        ans += cnt;
    }
    cout << max(ans - 1,0)<< endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, cnt, dist[N];
vector<int> g[N], v;
set<int> nodes;
queue<int> q;

void bfs(int node) {
    q.push(node);
    while(!q.empty()){
        int cur = q.front();
        q.pop();
        for(auto x : nodes){
            if(binary_search(g[cur].begin(),g[cur].end(),x) == false && x != cur){
                v.push_back(x);
                q.push(x);
            }
        }
        for(int i=0;i<v.size();i++)
            nodes.erase(v[i]);
        v.clear();
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 0, a, b; i < m; i++) {
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        sort(g[i].begin(), g[i].end());
        nodes.insert(i);
    }
    while (!nodes.empty()) {
        int node = *nodes.begin();
        nodes.erase(node);
        bfs(node);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, used[N], cnt, dist[N];
vector<int> g[N];

void dfs(int node) {
    used[node] = 1;
    vector<int> v;
    for (int i = node + 1; i <= n; i++) {
        if (used[i])continue;
        if (binary_search(g[node].begin(), g[node].end(), i) == false) {
            used[i] = 1;
            v.push_back(i);
        }
    }
    for (int i = 0; i < v.size(); i++)
        dfs(v[i]);
}

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++)
        sort(g[i].begin(), g[i].end());
    for (int i = 1; i <= n; i++) {
        if (used[i])continue;
        dfs(i);
        ans++;
    }
    cout << ans - 1 << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int n, m, ans, take[N], cnt = 1;
vector<int> g[N];

int main() {
    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        if(g[i].size() == 0)return cout << 0, 0;
        int add;
        if(take[i] == 0)add=1;
        else add = 0;
        sort(g[i].begin(),g[i].end());
       // cout << i << " -> ";
        int j = lower_bound(g[i].begin(),g[i].end(),i + 1) - g[i].begin();
       // cout << " j = " << j <<" " << g[i].size() << " " << g[i][j] <<" -> ";
        g[i].push_back(-1);
        int sz = g[i].size();
        for(int k = i + 1 ; !(n - k - 1 == sz - j && k == g[i][j]) && k <= n;k++){
         //   cout << k <<"  " << j << endl;
            if(g[i][j] == k){
                j++;
                continue;
            }
           // cout << k << " " << j  << " " << g[i][j]<< " nxt ";
            if(take[k] != 0)add=0;
            else cnt++;
            take[k] = i;
            if(cnt == n){
                cout << 0;
                return 0;
            }
        }
        //cout << add << endl;
        ans += add;
    }
    cout << ans - 1<< endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * froot;
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
//  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
//    if(cnt > 100)puts("wrong");
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
//    num[ro]++;
  }
  else return -1;
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(froot,-v) && se.find(v)==se.end()){
      insert(froot,-v);
//      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(froot,-v)){
      remove(froot,-v);
//      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
//    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      insert(froot,-i);
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n;
  while (l < r){
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v)){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    dfs(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && !find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  cin >> n >> m;
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN],vec2[MAXN];
int n,m,ans;
Node * froot;
int se[MAXN];
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
  }
  else return -1;
  ans--;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    if(!find(froot,-v) && !se[v]){
      insert(froot,-v);
    }
  }
  se[u]=1;
  while(true){
    int v = get_next(u);
    if(v == -1)break;
    vec2[u].push_back(v);
    se[v]=1;
  }
  for (auto v:vec[u]) {
    if(!se[v] && find(froot,-v)){
      remove(froot,-v);
    }
  }
  for (auto v:vec2[u]) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i) {
    if(!se[i]){
      insert(froot,-i);
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+20;
vector<int>vec[MAXN],vec2[MAXN];
int n,m,ans,vis[MAXN];
set<int>se;
void dfs(int u){
  if(ans==0)return;
  if(!vis[u])se.erase(u);
  vis[u]=1;
  for (auto v:vec[u])if(!vis[v])se.erase(v);
  for(auto v : se) {
//    cout << u << " u v "<< v << endl;
    vis[v]=1;
    ans--;
    vec2[u].push_back(v);
  }
  se.clear();
  for (auto v:vec[u])if(!vis[v])se.insert(v);
  for (auto v:vec2[u])if(!vis[v])dfs(v);
}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i)se.insert(i);
  for (int i = 1; i <= n; ++i) if(!vis[i])dfs(i);
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+20;
vector<int>vec[MAXN],vec2[MAXN];
int n,m,ans,vis[MAXN];
set<int>se;
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i)se.insert(i);
  for (int i = 1; i <= n; ++i) {
    if(!vis[i])se.erase(i);
    vis[i]=1;
    for (auto v:vec[i])se.erase(v);
    for(auto f : se) {
      vis[f]=1;
      ans--;
    }
    se.clear();
    for (auto v:vec[i])if(!vis[v])se.insert(v);
    if(ans==0)break;
  }
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * froot;
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
//  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
//    if(cnt > 100)puts("wrong");
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
//    num[ro]++;
  }
  else return -1;
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(froot,-v) && se.find(v)==se.end()){
      insert(froot,-v);
//      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(froot,-v)){
      remove(froot,-v);
//      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
//    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      insert(froot,-i);
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+20;
vector<int>vec[MAXN],vec2[MAXN];
int n,m,ans,vis[MAXN];
set<int>se;
void dfs(int u){
  if(ans==0)return;
  se.erase(u);
  vis[u]=2;
  for (auto v:vec[u])if(!vis[v])se.erase(v);
  for(auto v : se) {
//    cout << u << " u v "<< v << endl;
    vis[v]=1;
    ans--;
    vec2[u].push_back(v);
  }
  se.clear();
  for (auto v:vec[u])if(!vis[v])se.insert(v);
  for (auto v:vec2[u])if(vis[v]<2)dfs(v);
}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i)se.insert(i);
  for (int i = 1; i <= n; ++i) if(!vis[i])dfs(i);
  cout << ans << endl;
}