算数基本定理(求一个数所有约数的个数)——一道OJ题目

来源:互联网 发布:点胶机编程步骤 编辑:程序博客网 时间:2024/05/16 04:49

算数基本定理

大约公元前350年,欧几里得在他伟大的十三卷著作《原本》中,用了许多篇幅来讨论素数。特别是他证明了每一个比1大的数(即每个比1大的正整数)要么本身是一个素数,要么可以写成一系列素数的乘积,如果不考虑这些素数的在乘积中的顺序,那么写出来的形式是唯一的。

例如:14=2×7,21=3×7,等等。

等号右边的表达式分别是数14与21的“素数分解”。这样我们能把欧几里得的结果表达为:每一个大于1的奇数要么是素数,要么具有唯一的(次序变化不计)素数分解。这个事实被称为算术基本定理,它告诉我们素数好比化学家的原子——所有整数得以构成的基本砌块。

算术基本定理(The fundamental theorem of arithmetic) 即唯一分解定理, 告诉我们每一个大于1 的整数若不是质数都可以写成有限多个质因子的乘积且经过适当排序其写法唯一。

以下是一道OJ题目,网址:http://ac.jobdu.com/problem.php?pid=1493
/*题目描述:给定两个正整数a,b(1<=a,b<=100000000),计算他们公约数的个数。如给定正整数8和16,他们的公约数有:1、2、4、8,所以输出为4。输入:输入包含多组测试数据,每组测试数据一行,包含两个整数a,b。输出:对于每组测试数据,输出为一个整数,表示a和b的公约数个数。样例输入:8 1622 16样例输出:42*/

解法一:
思路:要求所有公约数的个数,我们可以先用辗转相除法求出最大公约数,然后求出这个最大公约数的所有约数的个数,也即a和b的公约数的个数
     #include <cstdio>#include <iostream>using namespace std;int main(){int a,b,temp;int count,max,i;freopen("f:/in.txt","r",stdin);while(~scanf("%d%d",&a,&b)){while(a%b!=0){temp=a%b;a=b;b=temp;} //辗转相除法求出最大公约数 max=b;count=0;if(max==1){printf("1\n");continue;}for(i=1;i<max;i++){if(b%i==0){count++;max=b/i; //由于该题卡时间,此处同时找到两个约数,减少遍历范围if(max!=i)       count++;}}printf("%d\n",count);}fclose(stdin);return 0;}
解法二:
对a、b分别分解成质因子,然后根据算数基本定理,求出公约数个数。
#include <cstdio>#include <iostream>#include <map>#include <set>using namespace std;int min(int a,int b){if(a>b)return b;return a;}int main(){map<int,int> fa,fb;set<int> h;int a,b,count,ct;freopen("f:/in.txt","r",stdin);while(~scanf("%d%d",&a,&b)){fa.clear();fb.clear();h.clear();//分解afor(int i=2;i*i<=a;i++){if(a%i==0){h.insert(i);//存放质数因子//求该质数因子的个数,存入mapwhile(a%i==0){fa[i]++;a/=i;}}}if(a>1) {fa[a]++;//最后一个质数因子h.insert(a);}//分解bfor(int j=2;j*j<=b;j++){while(b%j==0) //求该质数因子个数{fb[j]++;    b/=j;}}if(b>1)    fb[b]++;//最后一个质数因子count=0;set<int>::iterator it;count=1;for(it=h.begin();it!=h.end();it++){//若有n个相同的m质数因子,则有n+1种组合方式(0个m、1个m.....n个m),每一张组合与其后的其他质数因子的组合之一都形成一个约数ct=min(fa[*it],fb[*it])+1;  count*=ct;}printf("%d\n",count); // 1本身也是公约数}fclose(stdin);return 0;}





原创粉丝点击