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

这篇博客探讨了整数划分问题的扩展,包括最大加数不超过m的划分数、不超过m个正整数的划分数、正奇数的划分数以及互不相同正整数的划分数。通过递归算法,分别给出了各问题的解决方案,并提供了相应的递推公式和边界条件。此外,还证明了问题(1)和问题(2)的解是相同的。最后,给出了实际的代码实现并展示了输入样例及输出样例。
摘要由CSDN通过智能技术生成

11088 整数划分的扩展问题(优先做)
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0

题型: 编程题 语言: G++;GCC;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

提示

这四个问题,不但要分析递归关系,还要正确写出递归的边界,有时边界值错一个,结果都不一定对,因此要小心。

1, 问题(1)即为书上例2-5。

2, 问题(2)也可以这样来想:
设d[i][j]表示i划分为j份,视为i个球放入j个盒子的方法数。d[n][m]为题目问题(2)所求,d[i][j]有如下递推关系:
(1)j个盒子有空的,d[i][j]=d[i][j-1],把某一空盒子拿出来放一边
(2)j个盒子都不空,d[i][j]=d[i-j][j],每个盒子扣掉1个球
因此,d[i][j] = d[i][j-1] + d[i-j][j], j>1;
特别的有: d[i][0]=0, i>=1; d[i][1]=1, i>=1; d[0][j]=1, j>=0; d[i][j]=0, i<0&&j>=0

3, 问题(1)和问题(2)是结果是相同的。
可以证明,任何一个问题(1)的解都可以转化为另一个问题(2)的解,一一对应,因此计数相同。

------------------------ 这里插入一下证明过程 ------------------------
这个证明思路可以参考如下:
对正整数n进行划分,不超过m个的划分,视为n块立方体积木堆成m列,垂直的来看n=n1+n2+…+nm。
对每一个堆法,将视角旋转90度,即水平方向上看,其实都对应一个最大加数不超过m的划分。
因此,对正整数n进行划分,不超过m个的划分,换种视角,都对应于一个最大加数不超过m的划分。反之亦然。
所以,这种对应是一一对应。因此,不超过m个加数的划分数 = 最大加数不超过m的划分数。

如下图所示:
在这里插入图片描述

---------------------------- 该证明过程结束 -----------------------------

4, 设: Odd(I,J)表示I划分为J个正奇数的划分数; Even(I,J)表示I划分为J个正偶数的划分数.
有如下递推关系:
(1)Even(I,J) = Odd(I-J,J), 每个偶加数减掉1变为奇加数
(2)Odd(I,J) = Odd(I-1,J-1) + Even(I-J,J), 加数含1的方式数 + 加数不含1的方式数
(3)特别的: J>I || J<0, Odd(I,J)=0;
Odd(1,1)=1, Odd(2,1)=0, Odd(2,2)=1
J>I || J<0, Even(I,J)=0;
Even(1,1)=0, Even(2,1)=1, Even(2,2)=0

5, 思想: 转化为子集和问题: 集合{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)
(这里一个都没挑,值为0,也是一种方式,所以为1)

注意:在1、2问中,只要i或者j有一个为0,则划分数为0,所以不能按照题目的提示来写,直接分析对应情况即可

#include <iostream>
using namespace std;
int Q(int n, int m);
int EVEN(int n, int m);
int ODD(int n, int m);

// A(i,j)=最大加数不超过m的划分数=不超过m个正整数之和的划分数
int A(int i,int j){
    if((i==0)||(j==0)){
        return 0;
    }
    if((i==1)||(j==1)){
        return 1;
    }
    if(i<j){
        return A(i,i);
    }
    if(i==j){
        return A(i,j-1)+1;
    }
    return A(i,j-1)+A(i-j,j);
}

// 正偶整数之和的划分数
int EVEN(int i,int j){
    if(j>i||j<=0){
        return 0;
    }
    if(((i==1)&&(j==1)||(i==2)&&(j==2))){
        return 0;
    }
    if((i==2)&&(j==1)){
        return 1;
    }
    return ODD(i-j,j);
}

// 正奇整数之和的划分数
int ODD(int i,int j){
    if(j>i||j<=0){
        return 0;
    }
    if((i==2)&&(j==1)){
        return 0;
    }
    if(((i==1)&&(j==1))||(i==2)&&(j==2)){
        return 1;
    }
    return ODD(i-1,j-1)+EVEN(i-j,j);
}


int main()
{
    int i,j;
    cin>>i;
    cin>>j;
    int res1 = A(i,j);//(1)(2)问答案相同
    int res2 = 0;//(3)(4)问答案相同
    for(int k=1;k<=i;k++){     //从1到i个数
        res2+=ODD(i,k);
    }
    cout << res1 << " " << res1 << " " << res2 << " " << res2;
    cout << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值