神经元(prufer序列+dp)
Posted harrypotter-fan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了神经元(prufer序列+dp)相关的知识,希望对你有一定的参考价值。
题目描述:
你培育出了一些新型的神经元,它们可以有很多的轴突。
具体来说,对于第i个神经元,它有1~di条轴突,因此可以与1~di个神经元相连,可以将轴突看成无向图的边,假定每个神经元都是不同的。
现在你想知道,有多少种方案使得其中恰好k个神经元相连通,这里的连通需要保证任意两个神经元间有且仅有一条路径,方案数可能很大,你只需要对10^9+7取模输出。
两个方案是不同的当且仅当选择的神经元集合不同或其中有至少一条轴突(u,v)出现在一个方案但不出现在另一个方案。
题解:
首先了解一下prufer序列:https://www.cnblogs.com/zwfymqz/p/8869956.html
由prufer序列的性质我们可以知道:
每个长度为n-2的prufer序列对应一棵n个节点的无根树。
因此,我们可以枚举符合条件的prufer序列个数。
定义 dp[i][j][k] 表示考虑到第i个数,用了j个数,prufer序列长度为k的序列个数,
dp时枚举下一个数选择几次即可。
1 dp[0][0][0]=1; 2 for(int i=0;i<n;i++) 3 for(int j=0;j<=i;j++) 4 for(int k=0;k<=n-2;k++) 5 if(dp[i][j][k]) 6 dp[i+1][j][k]+=dp[i][j][k];//此数不选 7 dp[i+1][j][k]%=MOD; 8 for(int cnt=0;cnt<=d[i+1]-1&&k+cnt<=n-2;cnt++)//枚举此数选几次 9 dp[i+1][j+1][k+cnt]+=dp[i][j][k]*c[k+cnt][k];//在k+cnt个位置中选k个按顺序放上一序列的数,其余位置放此数 10 dp[i+1][j+1][k+cnt]%=MOD; 11 12 13 14 15
所以,我们还要预处理一下c[][]数组(c[i][j]表示从i个数中选j个数的方案数),具体求法如下:
1 void init() 2 for(int i=0;i<=n;i++) 3 c[i][0]=1; 4 for(int j=1;j<=i;j++) 5 c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;//第i个数可选可不选 6 7 8
完整代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MOD=1e9+7; const int N=105; int n,d[N]; ll c[N][N],dp[N][N][N]; void init() for(int i=0;i<=n;i++) c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD; int main() scanf("%d",&n); init(); for(int i=1;i<=n;i++) scanf("%d",&d[i]); dp[0][0][0]=1; for(int i=0;i<n;i++) for(int j=0;j<=i;j++) for(int k=0;k<=n-2;k++) if(dp[i][j][k]) dp[i+1][j][k]+=dp[i][j][k]; dp[i+1][j][k]%=MOD; for(int cnt=0;cnt<=d[i+1]-1&&k+cnt<=n-2;cnt++) dp[i+1][j+1][k+cnt]+=dp[i][j][k]*c[k+cnt][k]; dp[i+1][j+1][k+cnt]%=MOD; printf("%d ",n); for(int i=2;i<=n;i++) printf("%lld ",dp[n][i][i-2]); return 0;
以上是关于神经元(prufer序列+dp)的主要内容,如果未能解决你的问题,请参考以下文章
BSOJ 5445 -- 2018雅礼树 prufer序列 dp
HDU 5629 Clarke and tree dp+prufer序列
[Matrix-Tree][插值][容斥][prufer序列][DP]夕张的改造