1. 程式人生 > 實用技巧 >[CF11D] A Simple Task

[CF11D] A Simple Task

題目

求無向圖的簡單環個數,點數不大於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; }
View Code