求无向图的简单环个数,点数不大于19
根据数据范围很容易得知是状压dp,普遍想法是记录点数状态和最后一个点再进行延伸,但这样非常容易重复。
我们可以考虑将一个状态里最低的一位设为起点,每次只向高位进行延伸。最后判一下起点与终点是否相连,更新答案。(简称拆环成链)
注意这样还是有重复的,一个环顺时针逆时针会个算一次,除以二就好了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN=20; const int MAXM=(1<<19)+5; int N,M; int mp[MAXN][MAXN]; LL dp[MAXM][MAXN]; int main(){ scanf("%d%d",&N,&M); for(int i=1,u,v;i<=M;i++){ scanf("%d%d",&u,&v); u--;v--; mp[u][v]=mp[v][u]=1; } LL ans=0; for(int i=0;i<N;i++) dp[1<<i][i]=1; for(int mask=1;mask<(1<<N);mask++){ int st=0; for(;st<N;st++)if((mask>>st)&1) break; for(int en=st;en<N;en++)if(dp[mask][en]){ for(int i=st+1;i<N;i++)if(!((mask>>i)&1)){ if(!mp[en][i]) continue; dp[mask|(1<<i)][i]+=dp[mask][en]; if(mp[i][st]&& __builtin_popcount(mask|(1<<i)) >= 3) ans+=dp[mask][en]; } } } printf("%lld",ans/2); return 0; }
原文:https://www.cnblogs.com/EDawnpractice/p/14126883.html