計算機演算法設計與分析課本(王曉東著)課後演算法實現題1-3 最多約數問題
阿新 • • 發佈:2019-01-01
問題描述: 正整數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