- 环计数问题
- __builtin_ffs() 函数 find_first_set 返回最后一个1的位置,注意编号从1开始
- 构造汉明权重递增的排列 核心思想:枚举popcount+不断迭代
- 迭代方法:
for(int j=(1<<m)-1,t;j<(1<<n);t=j+lowbit(j),j=t|(((lowbit(t)/lowbit(j))>>1)-1))
- 至于这道题,选择编号最小的节点作为简单环的代表就好啦
#include <bits/stdc++.h>
using namespace std;
vector<int>a[19];
long long f[19][1<<19];
bool b[19][19];
int lowbit(int n)
{
return n&(-n);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
u--;
v--;
a[u].push_back(v);
a[v].push_back(u);
b[u][v]=b[v][u]=true;
}
for(int i=0;i<n;i++)
{
sort(a[i].begin(),a[i].end());
reverse(a[i].begin(),a[i].end());
f[i][1<<i]=1;
}
long long ans=0;
for(int m=2;m<=n;m++)
{
for(int j=(1<<m)-1,t;j<(1<<n);t=j+lowbit(j),j=t|(((lowbit(t)/lowbit(j))>>1)-1))
{
int i=__builtin_ffs(j)-1;
for(int k=i,s=j;s>0;s=s-lowbit(s),k=__builtin_ffs(s)-1)
{
if(k==i)
{
continue;
}
if((j>>k)&1)
{
int p=(j&(~(1<<k)));
for(int l=0;l<a[k].size();l++)
{
if(a[k][l]<i)
{
break;
}
if((j>>a[k][l])&1)
{
f[k][j]+=f[a[k][l]][p];
}
}
if(b[i][k]&&m>2)
{
ans+=f[k][j];
}
}
}
}
}
cout<<ans/2<<endl;
return 0;
}