题意:n个点m条边的一个图,求其中简单环共有多少个
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 19;
const int INF = 0x3f3f3f3f;
int read(){
int f = 1, x = 0;
char s = getchar();
while(s < '0' ||s > '9'){if(s == '-')f = -1; s = getchar();}
while(s >= '0' && s <= '9'){x = x * 10 + s - '0'; s = getchar();}
return x * f;
}
int n, m;
int lowbit(int x){for(int i = 0; i < n; i ++)if(x & (1 << i))return i;} //lowbit(S):找S二进制中最低非零位的位置
bool Map[MAXN + 5][MAXN + 5];
LL f[(1 << MAXN) + 5][MAXN + 5];//f[S][i]:点集S,此时访问到i点,起点为lowbit(S)
int main(){
LL ans = 0;
n = read(), m = read();
for(int i = 1; i <= m; i ++){
int x = read() - 1, y = read() - 1;
Map[x][y] = Map[y][x] = 1;
}
for(int i = 0; i < n; i ++)
f[1 << i][i] = 1;
for(int S = 1; S <= (1 << n) - 1; S ++){//枚举点集
for(int i = 0; i < n; i ++){//刷表只能由自己转移到别人
if(! f[S][i]) continue;//自己状态必须合法访问过
int p = lowbit(S);//p为当前集合S位置最小的一点
for(int j = p; j < n; j ++){//访问比起点大的点作为下一点
if(! Map[i][j]) continue;//必须与i连边
if(S & (1 << j)){//j访问到当前点集
if(j == p)//j正好为起点出现了圈
ans += f[S][i];//累加答案
}
else//状态转移
f[S | (1 << j)][j] += f[S][i];
}
}
}
printf("%lld\n", (ans - m) / 2ll);
return 0;
}