给出一个正整数aa,要求分解成若干个正整数的乘积,即a=a1×a2×a3×...×an,并且1<a1≤a2≤a3≤...≤an,问这样的分解的种数有多少。注意到a=a也是一种分解。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a(1<a<32768)。
输出
�n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数。
样例
输入数据 1
2
2
20
Copy
输出数据 1
1
4
要知道所有的可行方案,可以先把所有的方案列出来。
先确定递归条件,显然当所有的因子相乘等于n时,计数器加1;
很容易想到的第一个优化是sum>n时return
void dfs(int n,int k,int sum){//n是输入值,k是防止重复算的,如(2,2,5),(2,5,2),属于重复,后面的会讲
if(sum==n){
cnt++;
return;
}
if(sum>n)
return;}
接下来就是枚举了。
for(int i=k;i<=n;i++){//k会使后面的元素必大于等于前面的元素,所以防止重复计算
dfs(n,i,sum*i);
}
return;
到这里,已经可以算出n是小值了,但是n大了之后必超时。
第二个可以减时间复杂度的是,当i是n的因子时才进行递归。
for(int i=k;i<=n;i++){//k会使后面的元素必大于等于前面的元素,所以防止重复计算
if(n%i==0){
dfs(n,i,sum*i);}
}
return;
但是还是超了一个点,仔细想想,其实当sum>n的时候可以返回到上一个因子,如出现n=20,枚举的第一个结果是(2,2,2,2,2),这个时候已经超出n的值了,但是还会接着枚举(2,2,2,2,3),(2,2,2,2,4);注意之前的(if(sum>n),return)是回到调用他的地方,也就是会回到for循环,所以无法避免这种情况,因此想要避免这种没有意义的枚举,可以在for循环里面写
最后一个优化
for(int i=k;i<=n;i++){
if(sum*i>n)
return ;
if(n%i==0){
dfs(n,i,sum*i);}
}
return;
全部代码
#include <bits/stdc++.h>
using namespace std;
int cnt=0,sum;
void dfs(int n,int k,int sum){
if(sum==n){
cnt++;
return;
}
if(sum>n)
return;
for(int i=k;i<=n;i++){
if(sum*i>n)
return ;
if(n%i==0){
dfs(n,i,sum*i);}
}
return;
}
int main(){
int n,t;
cin>>t;
while(t--){
cnt=0;
cin>>n;
dfs(n,2,1);//k从2开始
cout<<cnt<<endl;}
}
本人新手,如有错误,欢迎大佬指出。