整数划分

整数划分

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 划分的个数为 f(n, m); 例如当 n = 4 时,有 5 个划分 {4}, {3,1}, {2,2}, {2,1,1}, {1,1,1,1};

该问题是求出 n 的所有划分个数,即 f(n, n)。下面考虑求 f(n,m) 的方法。

①、m = 1 || n = 1  只有一种划分情况,即 n 个 1 相加, 所以 f(n, m) = 1;

②、m = n > 1       f(n, m) = f(n, n-1) + 1  加上的 1 代表 n + 0 = n 这个划分方案

③、n < m           f(n, m) = f(n, n) 逻辑上不存在 m > n 的情况

④、n > m           f(n, m) = f(n, m-1) + f(n-m, m); 

f(n, m-1) 表示划分方案中没有 m 的情况,f(n-m, m) 表示划分方案中有 m 的情况。

整数划分

3、代码实现

#include <stdio.h>

/**
  *  @brief  整数划分问题,将一个整数划分为若干个数相加。例:整数 4,最大加数 4
         4 =4 + 0
         1+3=4
         1+1+2=4
         2+2=4
         1+1+1+1=4
     注意:1+3=4,3+1=4被认为是同一种划分方案
  *  @param   n   需要划分的数字
  *  @param   m   最大的加数
  */
int algorithm(int n, int m)
{
    if (n == 1 || m == 1) {  // 只要存在一个为 1,那么划分的方法数肯定只有一种,那就是 n 个 1 相加
        return 1;
    }
    else if (n == m && n > 1) { // 等价于:q(n, n-1) + 1; 最后面 +1 代表的是:0+n,这个划分的方案
        return algorithm(n, m - 1) + 1;
    }
    else if (n < m) { // 如果 m > n,那么令 m = n,因为最大加数在逻辑上不可能超过 n
        return algorithm(n, n);
    }
    else if (n > m) { // 分为两种:划分方案没有 m 的情况 + 划分方案有 m 的情况
        return algorithm(n, m - 1) + algorithm(n - m, m);
    }
    
    return 0;
}

int main()
{
    int r = algorithm(7, 7);
    printf("%d
", r);
    
    return 0;
}