[CF11D] A Simple Task
阿新 • • 發佈:2020-12-12
題目
求無向圖的簡單環個數,點數不大於19
題解
根據資料範圍很容易得知是狀壓dp,普遍想法是記錄點數狀態和最後一個點再進行延伸,但這樣非常容易重複。
我們可以考慮將一個狀態裡最低的一位設為起點,每次只向高位進行延伸。最後判一下起點與終點是否相連,更新答案。(簡稱拆環成鏈)
注意這樣還是有重複的,一個環順時針逆時針會個算一次,除以二就好了。
程式碼
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN=20; const int MAXM=(1<<19View Code)+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; }