题解 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; }
自己选择的路,跪着也要走完