题解 CF53E 【Dead Ends】

题意:

  给一个n(n<=10)个节点的无向图,图里面有m条边,以这m条边构建生成树,求所有生成树中只含有k个度数为1的点的方案数。

题解:

  看见这个数量级就一定会想到状态压缩dp...

       那让我们设计一下状态:

       dp[i][j] 表示生成树的状态为i时,所含的度数为1的点的状态j的方案数。

  那么就可以进行状态转移了,每次有两种更新方式:

                    1:加入一条边(也就是一个新点)到原来度数为1的点,相当于替换了。

                    2:把边加到一个度数不为1的节点上。

时间复杂度:

O(能过)

废话少说上代码:

#include<bits/stdc++.h>
using namespace std;
const int maxs=(1<<11)+10;
vector<int> mapp[20];
int dp[maxs][maxs],cnt1[maxs];
int n,m,k;
void init(){
    for(int i=1;i<=maxs;i++)
        for(int k=0;k<+15;k++)
            if(i&(1<<k))
               cnt1[i]++;
}
int main(){
    init();
    scanf("%d%d%d",&n,&m,&k);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y); x--;y--;
        mapp[x].push_back(y);mapp[y].push_back(x);
    }
    for(int i=1;i<=(1<<n)-1;i<<=1) dp[i][i]=1;
    for(int i=1;i<=(1<<n)-1;i++)
        for(int j=i;j;--j&=i)
            if(dp[i][j])
                for(int e=0;e<n;e++)
                    if(i&(1<<e))
                        for(int r=0;r<mapp[e].size();r++){
                            int to=mapp[e][r],now;
                            if(~i&(1<<to)){
                                if(cnt1[i]==1) now=i|(1<<to);
                                else now=j&~(1<<e)|(1<<to);
                                if(!(now>>to+1)) dp[i|(1<<to)][now]+=dp[i][j];
                            }
                        }
    long long ans=0;
    for(int i=0;i<=(1<<n)-1;i++) 
        if(cnt1[i]==k)
           ans+=dp[(1<<n)-1][i];
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/tonyshen/p/11628151.html