zoukankan      html  css  js  c++  java
  • 整数划分问题(递归法 或 母函数法 )

    样题:sdut2015寒假结训赛

    开始我还以为是用背包来做,但是写完了代码,怎么写就是不对,并且在实现的时候确实有点地方我用背包的算法描述不了!

    后来查到可以用:递归 或者 母函数算法!

    比赛时曾考虑过用递归来实现,但没有推导出来,后来发现别人的博客里面写着“整数划分问题”应该在讲解递归的时候就该学会了。

    我的心里顿时感到一股抱怨和悔恨,唉!当然自己的责任最大!

       整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:

       n=m1+m2+...+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,...,mi}为n的一个划分。

       如果{m1,m2,...,mi}中的最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);

       例如但n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

       注意4=1+3 和 4=3+1被认为是同一个划分。

    题目描述

    整数划分是一个非常经典的数学问题。
    所谓整数划分,是指把一个正整数n写成为n=m1+m2+...+mi的形式,其中mi为正整数,并且1<=mi<=n,此时, {m1, m2, ..., mi}为n的一个划分。如果{m1, m2, ..., mi}中的最大值不超过m,即max{m1, m2, ..., mi}<=m,那么我们称之为整数n的一个m划分。
    现在给出你正整数n和m,请你输出n的m划分的数量。
    例如,当n=4时,有5个划分,即{4}, {3,1}, {2,2}, {2,1,1}, {1,1,1,1}。
    注意,4=1+3和4=3+1被认为是同一个划分。

    输入

     输入文件以EOF结束。
    每组数据占一行,有两个正整数n和m。(n,m<=50)

    输出

     输出n的m划分的数量。

    示例输入

    4 4
    

    示例输出

    5
    数据量不大,递归算法实现:
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 unsigned long  GetPartitionCount(int n, int max)
     9 {
    10     if (n == 1 || max == 1)
    11         return 1;
    12     else if (n < max)
    13         return GetPartitionCount(n, n);
    14     else if (n == max)
    15         return 1 + GetPartitionCount(n, max-1);
    16     else
    17         return GetPartitionCount(n,max-1) + GetPartitionCount(n-max, max);
    18 }
    19 
    20 int main()
    21 {
    22     int n, m;
    23     long ans;
    24     while(scanf("%d %d", &n, &m)!=EOF)
    25     {
    26         ans = GetPartitionCount(n, m);
    27         printf("%ld
    ", ans );
    28     }
    29     return 0;
    30 }
    View Code

    递归算法分析: (剪辑地址:http://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html)

    根据n和m的关系,考虑以下几种情况: 

           (1)当 n = 1 时,不论m的值为多少(m > 0 ),只有一种划分即 { 1 };

            (2)  当 m = 1 时,不论n的值为多少,只有一种划分即 n 个 1,{ 1, 1, 1, ..., 1 };

            (3)  当 n = m 时,根据划分中是否包含 n,可以分为两种情况:

                  (a). 划分中包含n的情况,只有一个即 { n };

                  (b). 划分中不包含n的情况,这时划分中最大的数字也一定比 n 小,即 n 的所有 ( n - 1 ) 划分。

                  因此 f(n, n) = 1 + f(n, n-1);

            (4) 当 n < m 时,由于划分中不可能出现负数,因此就相当于 f(n, n);

            (5) 但 n > m 时,根据划分中是否包含最大值 m,可以分为两种情况:

                   (a). 划分中包含 m 的情况,即 { m, { x1, x2, ..., xi } }, 其中 { x1, x2, ..., xi } 的和为 n - m,可能再次出现 m,因此是(n - m)的 m 划分,因此这种划分

                         个数为 f(n-m, m);

                   (b). 划分中不包含 m 的情况,则划分中所有值都比 m 小,即 n 的 ( m - 1 ) 划分,个数为 f(n, m - 1);

                  因此 f(n, m) = f(n - m, m) + f(n, m - 1);

     

             综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况 (5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:

             f(n, m) =      1;                                        ( n = 1 or m = 1 )

                                f(n, n);                                 ( n < m )

                                1+ f(n, m - 1);                      ( n = m )

                                f(n - m, m) + f(n, m - 1);       ( n > m )

  • 相关阅读:
    2020,最新Model的设计-APP重构之路
    2020,最新APP重构:网络请求框架
    APP重构之路:引入单元测试
    接口测试中postman环境和用例集
    测试行业是该选择手动测试还是自动化测试?
    2020,必备自动生成测试脚本方案
    2020,必备自动化测试 之 “好用例、坏用例”
    2020,你需掌握go 单元测试进阶篇
    前端测试框架Jest——语法篇
    2020,测试生涯该如何转型升级?
  • 原文地址:https://www.cnblogs.com/yspworld/p/4318688.html
Copyright © 2011-2022 走看看