### Title Solution

Let's start with the simplest idea. First of all, we can see that the topic discovery \ (n \) is very small, so it's easy to think of state compression.

Let's consider a more intuitive state. f[i][j][k] represents the number of schemes of a simple ring whose starting point is I, the current point state is j, and the previous point state is K.

After careful consideration, we find that there is a problem in this state. The problem is that every point in each ring is calculated once.

So how to avoid this state? We consider that each ring is only contributed by the least numbered points.

After this operation, each ring is still calculated twice (clockwise once, counterclockwise once), but it doesn't matter much. Finally, divide the answer by 2.

Considering that the starting point is already the smallest point in the ring, we don't need to record it in the state.

Then, the state is transformed into f[i][j] to represent the number of schemes of simple rings whose current point state is I and the previous point state is j.

So how to transfer between States? Direct DP is difficult, so we use memory search.

In the memory search, a value should be recorded to indicate that several points have been to at present, because it is obvious that the number of points below 2 does not form a simple ring, but will be recorded to search for the answer, special judgment is enough.

### Code

#include <cstdio> namespace fast_IO{ const int IN_LEN = 10000000, OUT_LEN = 10000000; char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1; inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;} inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;} inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);} int read(){ int x = 0; int zf = 1; char ch = ' '; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar_(); if (ch == '-') zf = -1, ch = getchar_(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar_(); return x * zf; } void write(long long x){ if (x < 0) putchar_('-'), x = -x; if (x > 9) write(x / 10); putchar_(x % 10 + '0'); } } using namespace fast_IO; struct Edge{ int to, next; } edges[1005]; int head[20], edge_num = 0; inline void addEdge(int from, int to){ edges[++edge_num] = (Edge){to, head[from]}; head[from] = edge_num; } long long f[20][1048577]; int vis[20]; long long DFS(int frt, int u, int sta, int cnt){ vis[u] = 1; if (f[u][sta]) return f[u][sta]; for (int c_e = head[u]; c_e; c_e = edges[c_e].next){ int v = edges[c_e].to; if ((1 << (v - 1)) & sta){ if (cnt > 2 && v == frt) ++f[u][sta]; } else if (v > frt) f[u][sta] += DFS(frt, v, sta | (1 << (v - 1)), cnt + 1); } return f[u][sta]; } int main(){ int n = read(), m = read(); for (int i = 0; i < m; ++i){ int u = read(), v = read(); addEdge(u, v), addEdge(v, u); } long long ans = 0; for (int i = 1; i <= n; ++i) ans += DFS(i, i, (1 << (i - 1)), 1); write(ans / 2); flush(); return 0; }