分治法-整数划分(java)

问题:

将正整数n表示成一系列正整数之和n=n1+n2+…+nk(其中,n1>=n2>=…>=nk>=1,k>=1),求任意正整数n的划分数(n<10)。例如:
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;
1 + 1 + 1 + 1 + 1 + 1。

问题分析

假设我们将正整数n的所有不同的划分中,将最大加数n1小于等于m的划分个数定义为q(n, m)。那么如何来定义q(n,m)呢?
我们这里讨论的事分治,递归,那么显然这里我们要用到递归。那么如何来分析这个问题呢?
如果要递归,必须有个终结者,用于最后的返回。然后就是n和nk直接的关系。

算法设计

(1)首先我们需找终结者。分析的方法主要以m为特殊值来进行。
m = 1
q(n, 1) = 1, n >= 1;
最大加数小于等于1的划分只有一种, 1 + 1 + 1 + … +1
当m >= n, 由于n的划分中不可能出现,最大加数大于n的情况,所以得出
q(n, m) = q(n, n),m > = n
q(n, n) = q(n, n - 1) + 1, 这个等式也很好理解,q(n, n - 1),表示n排列中最大加数小于等于n - 1,那所有排列中只剩下一个了,就是n本身,也就是表示中的1。
这里需要注意的事q(n, n) = q(n, n -1) + 1的表达式,是在n和m相同情况下成立,这里并没有找到q(n,m)的通用关系,及m < n的时候
(2)寻找n和nk直接的关系
当m < n时,q(n, m)又如何呢,这里表示最大加数小于等于m的所有排列。根据上面的p(6)的例子。我们很容易推导出q(n, m) = q(n, m - 1) + x,而x是什么呢。
比如我们定义n为6,m为4,那么q(6, 4) = q(6, 3) + x, 这里我们知道q(6,4)所有排列中除掉q(6, 3)就剩下,以4开头的排列了。4开头的排列有多少呢?应该是所有2的排列,既所有6 - 4的排列。
这样我们就推导出通用的关系式了,q(n, m) = q(n, m - 1) + q(n - m, m),这个红色的m如何得到的?当然q(n,m)表示小于等于m的组合,那么q(n - m)里面当然不能大于m了。
总结下:

 q(n, m) = 1,                           n = 1, m =1  
         = q(n, n)                      n < m  
         = 1 + q(n, n -1)               n = m  
         = q (n, m - 1) + q(n - m, m)   n >m >1 

代码如下

import java .util.Scanner;
public class Main{
    public static void print(int[]str,int n,int m,int k) {//打印函数
        if (n > 0) {
            for (int i = n; i >= 1; i--) {//从大的数开始打印
                if (m == 0) {
                    System.out.println();//该数开头的数已经打印完了,换行
                    k++;
                }
                if (m == 0 || i <= str[m - 1]) {
                    str[m] = i;
                    print(str, n - i, m + 1, k);//递归调用

                }
            }
        } else {
            for (int i = 0; i <= m - 1; i++) {
                if (i == (m - 1)) {

                    if (k == (m - 1)) {
                        System.out.print(str[i]);
                    } else
                        System.out.print(str[i] + ",");
                }
                else {
                    System.out.print(str[i] + "+");
                }
            }
        }
    }
        public static int q(int n,int m){
            if(n<1||m<1)
                return 0;
            if(n==1||m==1)
                return 1;
            if(n<m)
                return q(n,n);
            if(n==m)
                return q(n,m-1)+1;
            return q(n,m-1)+q(n-m,m);
        }
        public static void main(String[]args){
        Scanner sc=new Scanner(System.in);
            System.out.println("请输入一个数:");
            int n=sc.nextInt();
            print(new int[n],n,0,-1);
            int result=q(n,n);
            System.out.println();
            System.out.println("对整数"+n+"的划分一共有:"+result+"种");
    }
}

运行示例

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值