问题描述: 正整数x的约数是能整除x的正整数。正整数x的约数个数记为div(x)。例如,1 2 5 10都是10的约数,且div(10)=4。设a和b是2个正整数,a<=b,找出a和b之间约数个数最多的数x。
算法设计: 对于给定的2个正整数a<=b,计算a和b之间约数个数最多的数。
数据的输入与输出: 输入文件示例 输出文件示例
1 36 9
问题分析: 可以用暴力求解的方法直接求出数的约数的个数,时间复杂度为O(n),随着数的增大时间复杂度也将增大,不合适,这里可以使用约数个数定理,n分解质因数 n=p1^a1 * p2^a2 * p3^a3 … pk^ak则n的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1),在求解质因数的过程中数字不断减小,时间复杂度为O(logN)
/*****************************************************************
source:算法课本实现题1-3
mean of the title:给定两个正整数,计算两个数之间约数个数最多的数
并输出此数的约数个数
版本2.0:约数个数定理,n分解质因数 n=p1^a1*p2^a2*p3^a3*…*pk^ak
则,n的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1)
*****************************************************************/
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int prime_num[10000];//存储质因子的个数
int isprime(int n){//判断n是否是质因数
bool flag = true;
for (int i = 2; i <= sqrt(n); i++){
if (n%i == 0){
flag = false;
break;
}
}
return flag;
}
int solve(int n){//求n的约数个数
memset(prime_num, 0, sizeof(prime_num));
int count = 1;
int num = n;
if (num == 1)
return 1;
if (isprime(num))
return 2;
for (int i = 2; i <= sqrt(num); i++){//分解质因子
if (!(n%i)){
prime_num[i]++;
n /= i;
i--;//还原i,质因子可能重复
}
}
for (int i = 2; i <= num; i++){
if (prime_num[i]){
//cout<<"prime_num["<<i<<"]="<<prime_num[i]<<endl;
count *= (prime_num[i] + 1);
}
}
return count;
}
int main(){
int a, b;
int max = 0;
cout << "Enter two integers a and b:";
cin >> a >> b;
for (int i = a; i <= b; i++){
if (solve(i)>max){
max = solve(i);
}
}
cout << "The largest number of divisor is " << max << endl;
return 0;
}
暴力求解的代码
#include<iostream>
#include<cmath>
using namespace std;
int main(){
int a,b;
int number,max=0;
cout<<"Enter two integers a and b:";
cin>>a>>b;
for(int i=a;i<=b;i++){
number=0;
for(int j=1;j<=sqrt(i);j++){
if(!(i%j)){
if(j!=(i/j))
number+=2;
else
number+=1;
}
}
if(number>max)
max=number;
}
cout<<"The largest number of divisor is "<<max<<endl;
return 0;
}
//时间复杂度为O((b-a)*sqrt(i)),随着b的增大,i增大,时间复杂度增长
附加
对于约数个数定理证明的一些个人思路
假设n=2^ n1 3^n3,那么n等于n1个2乘以n2个3,然后从n1个2中取一个2,那么从n2个3中就可以取(n2+1)个3和2相乘,每乘一次原数就会多出两个约数,如果从n1个2中取两个2,那么从n2个3中还是可以取(n2+1)个3和2个2相乘,那么原数就又会多出2(n2+1)个约数,那么扩展到n1个2,因为取0个2的时候36从n1个2中一共可以取(n1+1)个2(取0个2时是1和原数相乘),那么原数将一共有2*(n1+1)*(n2+1),因为有重复,所以最后要除以2