//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops")
//#pragma GCC target("avx,avx2")
//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

//# include <x86intrin.h>
# include <bits/stdc++.h>

# include <ext/pb_ds/assoc_container.hpp>
# include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;
 
template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define _USE_MATH_DEFINES_
#define ll long long
#define ld long double
#define Accepted 0
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x.size())
#define every(x) x.begin(),x.end()
#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define For(i,x,y)  for (ll i = x; i <= y; i ++) 
#define FOr(i,x,y)  for (ll i = x; i >= y; i --)
#define SpeedForce ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
// ROAD to...                                                                                                                                                                                                                Red

void setIn(string s) { freopen(s.c_str(),"r",stdin); }
void setOut(string s) { freopen(s.c_str(),"w",stdout); }
void setIO(string s = "") {
	// cin.exceptions(cin.failbit); 
	// throws exception when do smth illegal
	// ex. try to read letter into int
	if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
}

const double eps = 0.000001;
const ld pi = acos(-1);
const int maxn = 1e7 + 9;
const int mod = 1e9 + 7;
const ll MOD = 1e18 + 9;
const ll INF = 1e18 + 123;
const int inf = 2e9 + 11;
const int mxn = 1e6 + 9; 
const int N = 6e5+5;                                         
const int M = 22;
const int pri = 997;
const int Magic = 2101;

const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, -1, 0, 1};
mt19937 gen(chrono::steady_clock::now().time_since_epoch().count());
 
int rnd (int l, int r) {
	return uniform_int_distribution<int> (l, r)(gen);
}

int c[(1<<18)];
int e[18][18];
int dp[(1<<18)];
vector<int> w[18];

void solve() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < m; ++i) {
		int a, b;
		cin >> a >> b;
		--a, --b;
		e[a][b] = e[b][a] = 1;
	}
	
	for (int msk = (1<<n)-1; msk; --msk) {
		c[msk] = 1;
		for (int i = 0; i < n; ++i) if(msk&(1<<i)) {
			for (int j = i+1; j < n; ++j) if(msk&(1<<j) && e[i][j] == 0) {
				c[msk] = 0;
			}
		}
		dp[msk] = __builtin_popcount(msk);
		if(c[msk] && msk>0) {
			int lst = -1;
			for (int i = 0; i < n; ++i)
				if(msk&(1<<i)) {
					lst =i;
				}
			int wast = 0;
			
			for (auto x : w[lst]) {
				if((x&msk) == msk) {
					wast=1;
					break;
				}
			}
			if(!wast)
				w[lst].pb(msk);
			dp[msk] = 1;
		}
	}
	
	for (int i = 0; i < n; ++i) {
		for (int msk = 0; msk < (1<<n); ++msk) {
			if(msk&(1<<i)) {
				dp[msk^(1<<i)] = min(dp[msk^(1<<i)], dp[msk]);
			}
		}
	}
	
	for (int i = 0; i < n; ++i) {
		for (int msk = 0; msk < (1<<n); ++msk) {
			if(dp[msk] <= 1)
				continue;
			for(auto j : w[i])
				dp[msk] = min(dp[msk], dp[msk^(msk&j)] + 1); 
		}
	}
	cout << dp[(1<<n)-1] << '\n';
}

int main () {
	SpeedForce;
	
	int T = 1;
	//cin >> T;
	while(T--) solve();
	
	return Accepted;
}

// B...a

#include <bits/stdc++.h>

using namespace std;

#define ar array
#define ll long long
#define all(x) (x).begin(), (x).end()
ll a,b,n,m,adj[18],dp[1<<18],s[1<<18];
int chrom(){
    ll al=1<<n;
    ll bigp=1077563119;
    dp[0]=1;
    for(ll i=0;i<al;i++){
        if ((n-__builtin_popcount(i))%2){
            s[i]=1;
        }
        else{
            s[i]=-1;
        }
    }
    for(ll i=1;i<al;i++){
        int ctz = __builtin_ctz(i);
        dp[i]=dp[i-(1<<ctz)]+dp[(i-(1<<ctz))&adj[ctz]];
        dp[i]=dp[i]%bigp;
    }
    for(int k=1;k<n;k++){
        int ans=0;
        for(ll i=0;i<al;i++){
            s[i]=s[i]*dp[i];
            ans=ans+s[i];
        }
        if(ans!=0){
            return k;
        }
    }
    return n;
}
int main() {
    cin>>n>>m;
    memset(adj,0,sizeof(adj));
    for(int i=0;i<m;i++){
        cin>>a>>b;
        a=a-1;
        b=b-1;
        adj[a]|=1<<b;
        adj[b]|=1<<a;
    }
    cout<<chrom()<<endl;
    return 0;
}