zoukankan      html  css  js  c++  java
  • 神经元(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;
    }
  • 相关阅读:
    通信错误:(-1)[描述:无法解析路由器DDNS地址,请检查DDNS状态.] 解析办法
    小数量宽带用户的福音,Panabit 云计费easyradius 接口隆重发布,PA宽带计费系统
    送给那些经常问我如何设置360测速结果为电信的朋友,360测速模块原理简单分析
    Universal-Image-Loader(UIL)使用方法&流程图&源码分析 ----- 未完
    Android开发框架
    Android线程池的使用(未完)
    Android LruCache究竟是什么
    Java finally语句到底是在return之前还是之后执行?
    Android自定义图片加载框架
    Android 自定义View实现单击和双击事件
  • 原文地址:https://www.cnblogs.com/HarryPotter-fan/p/11405823.html
Copyright © 2011-2022 走看看