#include <bits/stdc++.h>
// #include <atcoder/all>
// using namespace atcoder;
#define rep(i, n) for (ll i = 0; i < (ll)(n); ++i)
#define rep2(i, s, n) for (ll i = s; i < (ll)(n); i++)
#define repr(i, n) for (ll i = n; i >= 0; i--)
#define pb push_back
#define COUT(x) cout << (x) << "\n"
#define COUTF(x) cout << setprecision(15) << (x) << "\n"
#define ENDL cout << "\n"
#define DF(x) x.erase(x.begin())
#define ALL(x) x.begin(), x.end()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(x.rbegin(), x.rend())
#define REVERSE(x) reverse(ALL(x))
#define MAX(x) *max_element(ALL(x))
#define MAXI(x) max_element(ALL(x)) - x.begin()
#define SUM(x) accumulate(ALL(x), 0ll)
#define COUNT(x, y) count(ALL(x), y);
#define ANS cout << ans << "\n"
#define YES cout << "YES\n";
#define NO cout << "NO\n";
#define Yes cout << "Yes\n";
#define No cout << "No\n";
#define init() \
  cin.tie(0);  \
  ios::sync_with_stdio(false)
#define debug(x) cerr << "[debug] " << #x << ": " << x << endl;
#define debugV(v)                       \
  cerr << "[debugV] " << #v << ":";     \
  rep(z, v.size()) cerr << " " << v[z]; \
  cerr << endl;
using namespace std;
using ll = long long;
using ld = long double;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using mll = map<ll, ll>;
using qll = queue<ll>;
using P = pair<ll, ll>;
using vp = vector<P>;
using vs = vector<string>;

template <typename T>
inline istream& operator>>(istream& i, vector<T>& v) {
  rep(j, v.size()) i >> v[j];
  return i;
}

template <typename T1, typename T2>
inline istream& operator>>(istream& i, pair<T1, T2>& v) {
  return i >> v.first >> v.second;
}

constexpr ll INF = 0x3f3f3f3f3f3f3f3f;
constexpr ld PI = 3.141592653589793238462643383279;
ll get_digit(ll x) {
  return to_string(x).size();
}

ll gcd(ll x, ll y) {
  return y ? gcd(y, x % y) : x;
}

ll lcm(ll a, ll b) {
  return a / gcd(a, b) * b;
}

template <class T>
void chmax(T& a, const T& b) {
  if (a < b) a = b;
}

template <class T>
void chmin(T& a, const T& b) {
  if (b < a) a = b;
}

ll N, M;
vll done, keiro;
vvll to;

void dfs(ll i) {
  if (done[i]) return;
  done[i] = 1;
  keiro.pb(i);
  for (ll t : to[i]) dfs(t);
}

vll colors;
ll cnt = 0;
void dfs2(ll i) {
  if (i == (ll)keiro.size()) {
    cnt++;
    return;
  }
  ll index = keiro[i];
  vll ng(3, 0);
  for (ll t : to[index])
    if (colors[t] != 0) ng[colors[t] - 1] = 1;
  rep(c, 3) {
    if (ng[c]) continue;
    colors[index] = c + 1;
    dfs2(i + 1);
    colors[index] = 0;
  }
}

signed main() {
  init();
  cin >> N >> M;
  done.resize(N);
  to.resize(N);
  rep(i, M) {
    ll a, b;
    cin >> a >> b;
    a--;
    b--;
    to[a].pb(b);
    to[b].pb(a);
  }

  ll ans = 1;
  colors = vll(N, 0);
  rep(i, N) {
    if (done[i]) continue;
    keiro = vll();
    dfs(i);
    cnt = 0;
    dfs2(0);
    ans *= cnt;
  }
  ANS;

  return 0;
}
#include<bits/stdc++.h>

using namespace std;

int n,m;
vector <int> f[233];

long long Ans = 1;
bool vis[233];
vector <int> v;
long long Now = 0;

void Find(int x)
{
	v.push_back(x);
	vis[x] = true;
	for(auto X : f[x])
	{
		if(vis[X]) continue;
		Find(X);
	}
}

int c[233];

void DFS(int Ind)
{
	if(Ind == v.size())
	{
		Now++;
		return ;
	}
	int x = v[Ind];
	for(int i=1;i<=3;i++)
	{
		bool flag = false;
		for(auto X : f[x])
		{
			if(c[X] == i) flag = true;
		}
		if(flag) continue;
		c[x] = i;
		DFS(Ind + 1);
		c[x] = 0;
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		f[x].push_back(y);
		f[y].push_back(x);
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]) continue;
		v.clear();
		Find(i);
		DFS(0);
		Ans = Ans * Now;
		Now = 0;
		
	}
	cout << Ans;
	return 0;
}