• 《训练指南》——6.9


    Uva11137

      立方体之和:输入正整数n(n10000),求将n写成若干个正整数的立方体之和有多少种方法。

      分析:这道题目其实就是基于递推的一道动态规划题目了,我们建立记录多状态的多段图,利用d[i][j]来表示立方数的底数不超过i且最终和为j的方法数,结合n的取值,有21^3 > 10000,因此这里的最终答案便是d[21][n].

      下面我们面临的问题就是如何求解d[i][j],即寻求递推关系。对于d[i][j],我们分成如下的两种情况:

    (i)和式当中最大的底数是i-1,则有d[i-1][j]种情况。

    (ii)和式当中最大的底数是i,则有d[i][j-i^3]种情况。

    可以看到,d[i][j]基于的子状态两个维度的参数都小于或等于ij,这放在动态规划当中,叫做无后效性。

     #include<cstdio>
    
    #include<cstring>
    
    using namespace std;
    
     
    
    int main()
    
    {
    
     
    
         long long d[23][10005];
    
         memset(d , 0 , sizeof(d));
    
           d[0][0] = 1;
    
         for(int i = 1;i < 23;i++)
    
              for(int j = 0;j < 10005;j++)
    
                {
    
                if(j-i*i*i >= 0)
    
                   d[i][j] = d[i-1][j] + d[i][j-i*i*i];
    
                else
    
                   d[i][j] = d[i-1][j];
    
                }
    
     
    
               // printf("%d
    ",d[1][0]);
    
     
    
        int n;
    
        while(scanf("%d",&n) != EOF)
    
        {
    
             printf("%lld
    ",d[22][n]);
    
        }
    
     
    
    }

    Uva11375(需要高精度,还没有A)

      火柴:用n(1n2000)根能够组成多少个非负整数?

      分析:我们设置d[i]恰好用i根火柴摆出不同的非负整数的个数。F[n]是本题结果,则显然有F[n] = d[i]。因此现在我们面临的问题是如何计算d[n]

      我们用c[x]记录拼出个位数x所需要的火柴数目,那么现在考察d[n]中的所有情况,为了便于找到递推关系,我们都去掉每一个整数的个位,这样我们能够找到如下的状态转移方程,或者说是递推方程:

      d[n] = d[n-c[i]],i[0,9].

      但是在编码实现的时候,并不是线性得求出d[1],d[2]…d[n],而是动态的更新d[1]d[2]…的值,从状态转移方程中能够看出,d[n]需要基于更小规模的子问题d[n-c[i]],因此这里我们首先设置一层循环遍历1~n作为d[]下标的参数,然后再进行“添加尾数”的操作,这样就有如下的状态转移方程:

      for i 0 to maxn

    for j 0 to 9

      d[i+c[j]] += d[i]

    简单的参考代码如下(Ps原题结果较大应用高精度运算)

    #include<cstdio>
    
    #include<cstring>
    
    using namespace std;
    
    const int maxn = 2005;
    
    int main()
    
    {
    
        int c[10] = {6,2,5,5,4,5,6,3,7,6};
    
        int d[maxn];
    
        memset(d , 0 , sizeof(d));
    
        d[0] = 1;
    
        for(int i = 0;i < maxn;i++)
    
              for(int j = 0;j < 10;j++)
    
                 if(!(i==0 && j==0) && i + c[j] < maxn)
    
                  d[i+c[j]] += d[i];
    
        int n;
    
           
    
        while(scanf("%d",&n) != EOF)
    
        {
    
              int sum = 0;
    
              for(int i = 1;i <= n;i++)
    
                   sum += d[i];
    
            printf("%d
    ",sum);
    
        }
    
     
    
       // printf("%d %d %d %d",d[2],d[3],d[4],d[5]);
    
    }
  • 相关阅读:
    SpringRMI解析3-RmiServiceExporter逻辑细节
    SpringRMI解析2-RmiServiceExporter逻辑脉络
    SpringRMI解析1-使用示例
    SpringMVC解析5-DispatcherServlet逻辑细节
    SpringMVC解析4-DispatcherServlet逻辑脉络
    SpringMVC解析3-DispatcherServlet组件初始化
    SpringMVC解析2-ContextLoaderListener
    算法笔记_074:子集和问题(Java)
    算法笔记_073:哈密顿回路问题(Java)
    算法笔记_072:N皇后问题(Java)
  • 原文地址:https://www.cnblogs.com/rhythmic/p/5576534.html
Copyright © 2020-2023  润新知