#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

using ii = pair<int,int>;
using ll = long long;

const int N = 705;
const int mod = 1e9 + 7;

vector<int>adj[N];
bool mat[N][N];
int n, m;
bool in[N] = {};
int cntParity[2];
bool checkClique(vector<int> v){
	memset(in, 0, sizeof in);
	for(auto x : v)in[x] = 1;
	for(auto x : v){
		int cnt = 0;
		for(auto y : adj[x])cnt += in[y];
		if(cnt != v.size())return false;
	}
	return true;
}
void kill(){cout << -1 << '\n';	exit(0);}
vector<int> g[N];
int col[N];
void dfs(int x, int c){
	if(col[x] != -1){
		if(col[x] != c)
			kill();
		return;
	}
	col[x] = c;
	cntParity[c]++;
	for(auto v : g[x])
		dfs(v,1-c);
}
int calc(int x){return x * (x-1) / 2;}
int main(){
#ifdef ONLINE_JUDGE
	ios_base::sync_with_stdio(0);
	cin.tie(0);
#endif // ONLINE_JUDGE

	cin >> n >> m;

	for(int i = 0, u, v; i < m; i++){
		cin >> u >> v;
		adj[u].push_back(v);
		adj[v].push_back(u);
		mat[u][v] = mat[v][u] = 1;
	}

	for(int i = 1; i <= n; i++){
			adj[i].push_back(i);	mat[i][i] = 1;
	}

	vector<int> firstClique	= adj[1], secondClique;

	for(int i = 1; i <= n; i++){
		if(find(firstClique.begin(), firstClique.end(), i) == firstClique.end())
			secondClique.push_back(i);
	}

	if(!checkClique(secondClique)){
		kill();
	}

	vector<int>Candidates;

	for(auto x : firstClique){
		int cnt = 0;
		for(auto y : adj[x])
			cnt += in[y];
		if(cnt == secondClique.size())
			Candidates.push_back(x);
	}


	for(auto x : Candidates){
		firstClique.erase(find(firstClique.begin(), firstClique.end(),x));
	}

	if(!checkClique(firstClique)){
		kill();
	}

//	cerr << ans << '\n';
//	cerr << firstClique.size() << ' ' << secondClique.size() <<' ' << Candidates.size() << '\n';
//
//	for(auto x : firstClique)cout << x << '\n';
//	for(auto x : secondClique)cout << x << '\n';


	bool f = true;

	while(f){
		f = false;
		vector<int>addToSecond, addToFirst;
		for(auto x : Candidates){
			int cnt1 = 0, cnt2 = 0;
			for(auto v : firstClique)cnt1 += mat[x][v];
			for(auto v : secondClique)cnt2 += mat[x][v];
			if(cnt1 != firstClique.size() || cnt2 != secondClique.size()){
				f = true;
				if(cnt2 == secondClique.size())
					addToSecond.push_back(x);
				else if(cnt1 == firstClique.size())
					addToFirst.push_back(x);
				else
					kill();
			}

		}

		for(auto x : addToFirst){
			firstClique.push_back(x);
			Candidates.erase(find(Candidates.begin(), Candidates.end(),x));
		}
		for(auto x : addToSecond){
			secondClique.push_back(x);
			Candidates.erase(find(Candidates.begin(), Candidates.end(),x));
		}

	}


	if(!checkClique(firstClique) || !checkClique(secondClique))
		kill();

	int sz1 = firstClique.size();
	int sz2 = secondClique.size();

	/*
	 * i have elements that have to be in the first clique
	 * elements that have to be in the second clique
	 * and elements that can be in both
	 * now if elements u and v in candidates are not connected by an edge
	 * they can't be in the same set hence they must have different colors
	 * so i bipartite check their compliment graph
	 */

	memset(col,-1,sizeof col);

	for(auto x : Candidates)
		for(auto y : Candidates)
			if(!mat[x][y]){
				g[x].push_back(y);
			}

	vector<pair<int,int>> vp;

	for(auto x : Candidates)
		if(col[x] == -1){
			cntParity[0] = cntParity[1] = 0;
			dfs(x,0);
			vp.push_back({cntParity[0], cntParity[1]});
		}

	int init1 = firstClique.size();
	int init2 = secondClique.size();

	vector<int> vals = {0};
	int tot = Candidates.size();

	for(auto x : vp){

		vector<int>nxt;

		for(auto v : vals)
			nxt.push_back(v + x.first),
			nxt.push_back(v + x.second);

		sort(nxt.begin(), nxt.end());
		nxt.resize(unique(nxt.begin(), nxt.end()) - nxt.begin());
		vals = nxt;
	}

	int ans = n * n;

	for(auto v : vals)
		ans = min(ans, calc(init1 + v) + calc(init2 + tot - v));

	cout << ans << '\n';

	return 0;
}


Measured memory_bytes: 3840