#
问题描述
一个正整数可以被分解成几个小于它的正整数的乘积,如下
对于指定的整数X, 乘积只能由小至大排列, 求共有多少种不同的乘积组合
如数字 X = 100, 可拆分为
1 * 100
2 * 50
2 * 2 * 25
2 * 2 * 5 * 5
2 * 5 * 10
2 * 5 * 2 * 5
4 * 25
4 * 5 * 5
5 * 20
5 * 2 * 10
5 * 4 * 5
10 * 10
10 * 5 * 2
黄色部分代表与上面出现过的情况重叠,仅交换律有区别
当 X= 100 时, 扣除黄色部分,总共9种情况
算法设计
#include <iostream>
using namespace std;
int comb(int n, int left=2){
if(n <= left) return 1;
int sum = 1;
for(int i=left; i<n/2; i++){
if(n%i != 0) continue;
int right = n/i;
if(i > right) return sum;
sum += comb(right, i);
}
return sum;
}
int main(){
int num;
cout << "Please input the number: ";
cin >> num;
cout << endl << "The amount of possible combinations is " << comb(num);
return 0;
}
程序逻辑
从1开始,遍历所有X的因子
如 X = 100
i | 因子 |
---|---|
2 | 50 |
3 | 非因子 |
4 | 25 |
5 | 20 |
6 | 非因子 |
… | 非因子 |
10 | 10 (特殊情况,i == n/i,退出循环返回1)(此处返回1而不是0的原因是,10*10亦是一种可接受的情况) |
11 | 非因子 |
… | 非因子 |
20 | 5 (程序不会执行到这里) |
然后i=2时,因子里的50可以用递归计算,如此类推
递归的返回条件是,当n <= left,返回1
因为当left大于n,则无法分解
比如求2大于5 的因子,结果是没有,因此返回1
此处不是返回0 的原因是,我们默认1×n是一种可接受的情况
程序有两个参数:
n: 需要分解的数字
如当 X = 100 时, 需要分解的数字则为100
left: 上一个需要分解的数字,如下
2 × 50
= 2 * 2 * 5 * 5
此轮需要分解的数字为50
上一个需要分解的数字则为2
之所以需要记录上一个需要分解的数字是因为我们只考虑数字由大到小排列的情况
所以需要left传入循环开始的位置
避开计算小于left的数字
加上if(i > right) return sum;
当右边的数字越来越小,比左边的i还小时,退出循环返回sum
就能达到左边的数字只能比右边的数字大的效果
最后加和递归,我们得到答案