`

11088 整数划分问题

 
阅读更多

11088 整数划分的扩展问题(必做)

时间限制:1000MS  内存限制:65535K
提交次数:0 通过次数:0

题型: 编程题   语言: C++;C;VC;JAVA

Description

下面有整数划分问题扩展出的多个题例:
(1)正整数n划分为若干正整数之和,最大加数不超过m的划分数
(2)正整数n划分为不超过m个正整数之和的划分数
(3)正整数n划分为若干正奇整数之和的划分数
(4)正整数n划分为互不相同正整数之和的划分数
约定:
整数划分无顺序,比如对7划分,认为2 2 3和3 2 2和2 3 2为同一种划分。



输入格式

两个数n和m,中间空格相连。n和m都不超过100。

如输入7 3
则:最大加数不超过3的划分为:(3 3 1)(3 2 2)(3 2 1 1)(3 1 1 1 1)(2 2 2 1)(2 2 1 1 1)(2 1 1 1 1 1)(1 1 1 1 1 1 1),共8种。
不超过3个正整数的划分为:(7)(6 1)(5 2)(5 1 1)(4 3)(4 2 1)(3 3 1)(3 2 2),共8种。
若干正奇数的划分为:(7)(5 1 1)(3 3 1)(3 1 1 1 1)(1 1 1 1 1 1 1),共5种。
互不相同正整数的划分为:(7)(6 1)(5 2)(4 3)(4 2 1),共5种。


输出格式

四个数,中间空格相连,分别为上面四个题例的结果。其中m参数只和题例(1)和(2)有关,与(3)(4)无关


输入样例

7 3


输出样例

8 8 5 5


提示


 

整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数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的所有划分个数,即f(n, n)。下面我们考虑求f(n,m)的方法;

 

        ---------------------------------------------------------------------

                                           (一)

        ---------------------------------------------------------------------

       根据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 )

        ---------------------------------------------------------------------

                                           (二)

        ---------------------------------------------------------------------

思想: 转化为子集和问题: 集合{1,2,…,n},挑选若干正整数,使之和为n,这也是一个背包装物品问题。
设F(I,J): 表示挑选集合前I个,使之和为J的方式数。
递推关系: F(I,J) = F(I-1,J) + F(I-1,J-I), 第I个不挑的方式数 + 挑第I个的方式数
递推边界: F(1,1)=1, F(1,k)=0(k>1), F(I,k)=0(k<0), F(I,0)=1(I>0)
 
#include <iostream>
 
using namespace std;
int m,n;
int f1(int n,int m)
{
    if(n<1||m<1) //不为负数
        return 0;
    if(m==1||n==1)  //1的m划分 或 n的1划分 都是 1
        return 1;
    if(n==m)  // 含n是 1 不含的是 n 的 n-1 划分
        return 1+f1(n,n-1);
    if(n<m)  // 最大也是n 即 n 的 n 划分
        return f1(n,n);
    // 含 m 的是 n-m 的 m 划分 因为 n-m中可能再次出现m
    // 不含 m 的是 n 的 m-1 划分
        return f1(n-m,m)+f1(n,m-1);
}
 
int f2(int n,int m)
{
    if(m==0) //F(I,0)=1(I>0)
        return 1;
    if(m<0) //F(I,k)=0(k<0)
        return 0;
    if(n==1&&m==1) //F(1,1)=1
        return 1;
    if(n==1&&m>1)  //F(1,k)=0(k>1)
        return 0;
 
//设F(I,J): 表示挑选集合前I个,使之和为J的方式数。
// F(I,J) = F(I-1,J) + F(I-1,J-I), 第I个不挑的方式数 + 挑第I个的方式数
    return f2(n-1,m)+f2(n-1,m-n);
}
int main()
{
    cin >> n >> m;
 
    cout << f1(n,m) <<" "<< f1(n,m) << " ";
    cout << f2(n,n) <<" "<< f2(n,n) << endl; //m参数与(3)(4)无关
    return 0;
}

 #include <iostream>

 

using namespace std;

int m,n;

int f1(int n,int m)

{

    if(n<1||m<1) //不为负数

        return 0;

    if(m==1||n==1)  //1的m划分 或 n的1划分 都是 1

        return 1;

    if(n==m)  // 含n是 1 不含的是 n 的 n-1 划分

        return 1+f1(n,n-1);

    if(n<m)  // 最大也是n 即 n 的 n 划分

        return f1(n,n);

    // 含 m 的是 n-m 的 m 划分 因为 n-m中可能再次出现m

    // 不含 m 的是 n 的 m-1 划分

        return f1(n-m,m)+f1(n,m-1);

}

 

int f2(int n,int m)

{

    if(m==0) //F(I,0)=1(I>0)

        return 1;

    if(m<0) //F(I,k)=0(k<0)

        return 0;

    if(n==1&&m==1) //F(1,1)=1

        return 1;

    if(n==1&&m>1)  //F(1,k)=0(k>1)

        return 0;

 

//设F(I,J): 表示挑选集合前I个,使之和为J的方式数。

// F(I,J) = F(I-1,J) + F(I-1,J-I), 第I个不挑的方式数 + 挑第I个的方式数

    return f2(n-1,m)+f2(n-1,m-n);

}

int main()

{

    cin >> n >> m;

 

    cout << f1(n,m) <<" "<< f1(n,m) << " ";

    cout << f2(n,n) <<" "<< f2(n,n) << endl; //m参数与(3)(4)无关

    return 0;

}

 

分享到:
评论

相关推荐

    11088 整数划分的扩展问题

    根据给定的信息,我们可以推断出这是一个与整数划分(Integer Partition)相关的算法问题。整数划分是指将一个正整数表示为多个正整数之和的方法,且这些加数的顺序不重要。例如,数字4可以被划分为4、3+1、2+2、2+1...

    整数划分问题(实现代码)

    整数划分问题的实现代码 整数划分问题是将一个正整数 n 拆成一组数连加并等于 n 的形式,且这组数中的最大加数不大于 n。这是一种经典的组合数学问题,具有重要的理论价值和实践应用价值。 在解决整数划分问题时,...

    整数划分问题、具体算法实现

    整数划分问题是一个经典的计算机科学问题,主要涉及组合优化和图论领域。在数学上,它指的是给定一个正整数n,寻找所有可能的方法将其分成若干个正整数的和,每个正整数称为一个部分。每个不同的部分组合构成一个...

    整数划分问题

    ### 整数划分问题详解 #### 一、整数划分问题概述 整数划分问题是一个经典的组合数学问题,主要研究如何将一个正整数分解为若干个正整数之和的不同方式。这个问题不仅在数学领域有广泛的应用,在计算机科学、算法...

    整数划分问题 回溯法 深度优先遍历

    整数的分划问题 将正整数n表示成一系列正整数之和,n=n1+n2+...+nk,其中n1&gt;n2&gt;...&gt;nk,k&gt;=1。正整数n的不同划分个数称为n的划分数

    整数划分问题java源码

    整数划分问题是一个经典的计算机科学中的算法问题,它在数学和计算机科学的多个领域都有应用。在这个Java源码中,我们可以看到如何解决这个问题。中国科学技术大学软件学院的《算法设计与分析》课程通过这个实验,...

    整数划分,并输出结果

    ### 整数划分算法解析与实现 ...该程序实现了对任意正整数`n`的所有可能的划分组合的计算和输出,通过递归的方式解决了整数划分问题。在实际应用中,整数划分问题有广泛的应用场景,如密码学、组合优化等领域。

    整数划分代码实现

    当N大于1时,我们可以选择是否包含某个数字i(1≤i≤N),然后递归地处理剩余的整数划分问题。以下是一个简单的递归实现: ```c #include void integerPartition(int n, int current) { if (n == 0) { printf(...

    中科大算法导论课程实验 整数划分 代码

    **整数划分问题** 整数划分是组合优化领域的一个经典问题,源于数学和计算机科学。在整数划分问题中,我们需要找到一个非负整数序列(可以为空),使得这些整数之和等于给定的正整数S,且序列中的每个元素都不相同...

    java算法分析与设计之整数划分问题源代码

    java算法分析与设计之整数划分问题源代码 算法作为计算机专业学生的必修课,同时也是软件开发过程中必备的编程思想,对学习研究计算机专业意义重大;正因为这门课程难,所以除了相关方面的书籍,网络资源少的可怜,...

    整数划分的解析

    整数划分是计算机科学中的一种经典算法问题,主要研究如何将一个正整数拆分成一组非负整数的和,且这些整数的和恰好等于原数。在本例中,我们关注的是最大加数不超过原数的整数划分。这个问题涉及到递归思想和数学...

    整数划分输出划分情况

    算法:整数划分问题,将一个整数n表示成一系列正整数之和。

    整数划分问题(回溯法).mp4

    最近我写了一篇csdn文章:【算法设计与分析】——整数划分问题(回溯法),并且画了一个流程图,为了让大家更加清楚的理解我讲的内容,所以我给大家录了一个讲解视频,希望大家一起进步哦~

    整数划分方法2及代码(有注释)

    整数划分问题的基本思想是找到所有可能的方式,将一个整数N分解为一个或多个正整数的和。例如,对于N=5,可能的划分有:5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1。每一种方式都代表了一种不同的组合。 整数...

    整数划分方法1及代码(有注释)

    在整数划分问题中,递归通常从最大的正整数开始,然后尝试减少这个数并增加下一个较小的数,以保持总和不变,直到所有可能的划分都被考虑。 以下是整数划分方法1的基本步骤: 1. **基本情况**:当总和为0时,表示...

    整数划分的回溯法表示

    整数划分问题是一个经典的组合数学问题,指的是将一个正整数拆分成若干个正整数之和的方法数。例如,数字6可以被拆分为`6`, `5+1`, `4+2`, `4+1+1`, `3+3`, `3+2+1`, `3+1+1+1`, `2+2+2`, `2+2+1+1`, `2+1+1+1+1`, `...

    C#整数划分源码 整数划分源码

    整数划分在计算机科学中是一个经典的数学问题,特别是在算法设计和数据分析领域有着广泛的应用。它涉及到将一个给定的正整数N分解为若干个正整数的和,这些正整数可以是任意顺序,但不能重复。这个问题在C#编程语言...

Global site tag (gtag.js) - Google Analytics