#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

//union-find
struct uni
{
	vector<int>par,siz;
	int g_;
	uni(int n):par(n),siz(n,1LL),g_(n)
	{
		for(int i=0;i<n;i++)par[i]=i;
	}
	void init(int n)
	{
		par.resize(n);
		siz.assign(n,1LL);
		for(int i=0;i<n;i++)par[i]=i;
	}
	void merge(int x,int y)
	{
		int rx=root(x);
		int ry=root(y);
		if(rx==ry)return;
		g_--;
		if(siz[rx]<siz[ry])swap(rx,ry);
		siz[rx]+=siz[ry];
		par[ry]=rx;
		return;
	}
	int grcount(){return g_;}
	int root(int x){return par[x]==x?x:par[x]=root(par[x]);}
	bool same(int x,int y){return root(x)==root(y);}
	int size(int x){return siz[root(x)];}
};
int bitsum(int bit)
{
	int r=0;
	for(int i=1;i<=bit;i<<=1)if(i&bit)r++;
	return r;
}
main()
{
	int n,m;cin>>n>>m;
	vector<pair<int,int>>ab(m);
	for(auto&[a,b]:ab){cin>>a>>b;a--;b--;}
	long ans=0;
	for(int bit=0;bit<1<<n;bit++)
	{
		uni uf(2*n);
		int flag=0;
		for(auto[a,b]:ab)
		{
			if(!(bit&1<<a)&&!(bit&1<<b)){flag=1;break;}
			if((bit&1<<a)&&(bit&1<<b))uf.merge(a,b+n),uf.merge(b,a+n);
		}
		if(!flag)
		{
			for(int i=0;i<n;i++)if(uf.same(i,i+n)){flag=1;break;}
			if(!flag)ans+=pow(2,uf.grcount()/2-(n-bitsum(bit)));
		}
	}
	cout<<ans<<endl;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double dbl;
#define REP(i, n) for (ll i = 0; i < ll(n); ++i)
#define REPD(i, n) for (ll i = n - 1; i >= 0; i--)
#define FOR(i, a, b) for (ll i = a; i <= ll(b); i++)
#define FORD(i, a, b) for (ll i = a; i >= ll(b); i--)
#define FORA(i, I) for (const auto &i : I)
#define ALL(x) x.begin(), x.end()
#define SIZE(x) ll(x.size())
const ll INF = 1LL << 60;
const ll MOD = 1'000'000'007LL;
const dbl EPS = 1e-12;
const dbl PI = 3.14159265358979323846;
#define coutALL(x)                                \
    for (auto i = x.begin(); i != --x.end(); ++i) \
        cout << *i << ' ';                        \
    cout << *--x.end() << endl;
ll myceil(ll a, ll b)
{
    return (a + (b - 1)) / b;
}
ll myfloor(ll a, ll b) { return a / b; }
template <class T>
inline bool chmax(T &a, T b)
{
    if (a < b)
    {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
inline bool chmin(T &a, T b)
{
    if (a > b)
    {
        a = b;
        return 1;
    }
    return 0;
}

using Graph = vector<vector<int>>;

vector<bool> seen;
vector<int> colors;
bool valid(const Graph &G, int v, int color)
{
    for (auto nx : G[v])
    {
        if (colors[nx] == color)
            return 0;
    }
    return 1;
}
void dfs(const Graph &G, int v, vector<int> &nodes)
{
    if (seen[v])
        return;
    nodes.push_back(v);
    seen[v] = true;
    for (auto next : G[v])
    {
        dfs(G, next, nodes);
    }
}
void colornize(const Graph &G, const vector<int> &nodes, int idx, ll &num)
{
    if (idx == nodes.size())
    {
        num++;
        return;
    }
    for (int color = 1; color <= 3; ++color)
    {
        if (valid(G, nodes[idx], color))
        {
            colors[nodes[idx]] = color;
            colornize(G, nodes, idx + 1, num);
            colors[nodes[idx]] = 0;
        }
    }
}

void solve()
{
    int N, M;
    cin >> N >> M;
    Graph G(N);
    REP(i, M)
    {
        int a, b;
        cin >> a >> b;
        --a;
        --b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    seen.assign(N, false);
    colors.assign(N, 0);
    vector<int> nodes;
    ll ans = 1;
    REP(start, N)
    {
        if (seen[start])
            continue;
        nodes.clear();
        dfs(G, start, nodes);
        ll tmp = 0;
        colornize(G, nodes, 0, tmp);
        ans *= tmp;
    }
    cout << ans << endl;
}
signed main()
{
    cout << fixed << setprecision(15);
    solve();
    return 0;
}