题意:在图中找简单回路
/*************
看了大神的博客才有所感悟啊,记忆化搜索+状态压缩。。。。太神了...
这种复杂度,近百万的DFS复杂度居然没有TLE,果然经验不足,菜鸟一只。
用状态压缩枚举起点和可能经过的点。
可以判定的简单通路 i->j,存在的条数为sum(i->k) 其中k,j之间有边。
当然,每次计算通路个数的时候,可以借每一个k来判断回路的条数,当然只能算一次。
这样加出来的回路会有重复,因为可能把顺逆两种方向运动的回路都考虑进去。
记忆化搜索的好处是可以精确的计算每次遍历点的情况,而如果单纯只是循环的话,却没有这么
灵活。
****************/
#define LL long long
#include<cstdio>
#include<cstring>
const int LMT=22,LMS=1<<19;
LL dp[LMS][LMT],ans;
int n,start,tem,gra[LMT][LMT];
int get_one(int x)
{
int res=0;
do
res+=x&1;
while(x>>=1);
return res;
}
int left(int x)
{
int d=x&(-x),res=0;
while(d>>=1)res++;
return res;
}
LL dfs(int mas,int end)
{
if(dp[mas][end]>=0)return dp[mas][end];
LL res=0;
for(int j=start;j<n;j++)
if(gra[j][end]&&((1<<j)&mas)&&(tem==2||j!=start))
{
tem--;
res+=dfs(mas^(1<<end),j);
tem++;
}
if(tem>2&&gra[end][start])
ans+=res;
dp[mas][end]=res;
return res;
}
int main(void)
{
int m,lim;
scanf("%d%d",&n,&m);
memset(dp,-1,sizeof(dp));
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
u--;v--;
gra[u][v]=gra[v][u]=1;
}
lim=1<<n;
for(int i=0;i<n;i++)dp[1<<i][i]=1;
for(int t=0;t<lim;t++)
{
start=left(t);
tem=get_one(t);
for(int j=start;j<n&&tem>1;j++)
if(gra[j][start]&&((1<<j)&t))
dfs(t,j);
}
printf("%I64d\n",ans>>1);
return 0;
}