[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

 

posted @ 2020-12-12 21:14  EDawn  阅读(106)  评论(0)    收藏  举报