2749:分解因数
总时间限制:1000ms 内存限制:65536kB
描述
给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * ... * an,并且1 < a1 <= a2 <= a3 <= ... <= an,问这样的分解的种数有多少。注意到a = a也是一种分解。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a (1 < a < 32768)
输出
n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数
样例输入
2
2
20
样例输出
1
4
i = 2~an,通过an%i ==0来判断i是不是an的因数,如果是,则由an/i作为参数进一步带入函数来判断直至an/i == i,(此时i为最后一个因数)。首先需知道f(m,n)的含义——求n中从m开始到n/m所有分解种数的和。而为什么每次只要满足上面的条件就算一种情况呢?这不妨举个例子当n = 100时,2、50算一种情况,而50可以继续分为2、25,这就有了2、2、25这种情况,再继续分,且每次分都能成为其一种分解情况所以a++。
下面另一种写法,区别在于分解次数加一是在每种分解情况完成时进行的,加的顺序是从分解到的最小因子开始加起,如对n = 100时一次调用f(2, 50) ,然后f(2, 25) ,f(2, 5), f(5, 5) (每次调用到f(x, x),相当于一种情况,后面变成f(x,1)然后直接a++)则先是递归到2 2 5 5 a++ 后,回溯到f(2, 25), 再是f(25, 25)时相当于2 2 25的情况然后a++ ,然后在回溯到f(2, 50) , f(50, 50),a++,这样对i ~ n/i中的分解情况累加。
再对for循环中的循环条件进行分析,他不会出现对两个相同情况2 50 和 50 2重复a++, 当i = 50 时,调用f(50,2) (f(50, 100/2))时会直接不满足条件而退出。而还要设i<=n, 是为了保证在回溯过程中将f(25, 25) 这样的情况给加上。
而这种情况实现方法像上面提到的虽然不计算重复情况,但还是会执行判断,会更耗时。
C++AC代码:
#include<iostream>
using namespace std;
int a;
void f(int m, int n) {
if(n == 1) {
a++;
return ;
}
else for(int i = m; i <= n; ++i)
if(n % i == 0){
f(i, n/i);
}
}
int main() {
int n;
cin >> n;
while(n--){
a = 0;
int x;
cin >> x;
f(2, x);
cout << a << endl;
}
}
而下面这种实现更是递归最典型的用法,是自顶向下的递归实现思路。从x开始向1递归,对1到x的每位进行判断(是否是其最大因子)累加次数的同时,加上下次递归的f(a, b-1)的情况,f(a, b)中若a%b == 0 则,进一步递归分解。否者对b-1进行判断。b减到1时结束返回0(可以想象一个质数只有第一次加一,后面b一直在减一,直到b == 1则返回0),而被分解的数a等于1,意味着上次调用时的因数刚好将其整除尽,算作一种情况返回1。
#include<iostream>
using namespace std;
int count(int a, int b) {
if(a == 1)//when a == b then a/b == 1 then sum++
return 1;
if(b == 1)//border
return 0;
if(a % b == 0)
return count(a/b, b) + count(a, b-1);//use f(a,b-1) to get cycle from n-1 to 2
else
count(a, b-1);
}
int main() {
int n;
cin >> n;
while(n--) {
int x;
cin >> x;
cout << count(x, x) << endl;
}
}
---------------------
作者:会悟
来源:CSDN
原文:https://blog.csdn.net/github_39329077/article/details/83378754
版权声明:本文为博主原创文章,转载请附上博文链接!