HDU 1108 最小公倍数【欧几里得算法】【更相减损术】【stein算法】
2015-07-10 15:07
453 查看
最小公倍数
Problem Description给定两个正整数,计算这两个数的最小公倍数。
Input
输入包含多组测试数据,每组只有一行,包括两个不大于1000的正整数.
Output
对于每个测试用例,给出这两个数的最小公倍数,每个实例输出一行。
Sample Input
10 14
Sample Output
70
注意 :
1:最小公倍数 = a*b/最大公约数 注意超过范围32位
用a*(b/最大公约数)就不会超过32位了
2:最大公约数GCD a%b 用较大的a%较小的b 若a%b!=0 ,再反复求余 一直到a%b==0 为止 b 就是最大公约数
3:欧几里得算法(非递归方式)
int gcd(int da,int xiao) { int temp; while (xiao!=0) { temp=da%xiao; da=xiao; xiao=temp; } return(da); }
#include<stdio.h> int GCD (int a,int b)//最大公约数 { int t; if(a<b){ t=a; a=b; b=t; } if(a%b==0){ return b; } else{ return GCD(b,a%b);//欧几里得递归形式 也可表示为return a%b?GCD(b,a%b):b; } } int LCM (int a,int b)//最小公倍数 { return a/GCD(a,b)*b; } int main (void) { int a,b; while(~scanf("%d%d",&a,&b)){ printf("%d\n",LCM(a,b)); } return 0; }
1、辗转相除法又称欧几里得算法(求最大公约数)
思路:
第一步 两个整数的最大公约数等于其中较小的数和两数的相除余数的最大公约数
第二步 利用最大公约数求最小公倍数 设两个数是a,b最大公约数是p,最小公倍数是q, 那么有这样的关系:ab=pq 所以q=ab/p
#include <stdio.h> main() { unsigned int i,j,n,temp,a; scanf("%d",&n); while(n--) { scanf("%d%d",&i,&j); //两个数的积 作为后面求最小公倍数用 a=i*j; //找到最大数 j if (i>j) { temp=i; i=j; j=temp; } //辗转相除法 while(temp=j%i) { j=i; i=temp; } printf("%d %d\n",i,a/i); } }
复杂度: 辗转相除法的运算速度为 O(n),其中 n 为输入数值的位数。
缺陷: 欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来。
一般实际应用中的整数很少会超过64位(当然现在已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。
2、更相减损术
思路:
任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
#include <stdio.h> main() { int i,j,m,c,proc,gcd; scanf("%d",&m); while(m--) { scanf("%d%d",&i,&j); c=0; proc=i*j; //执行第一步 同为偶数 就除2 while (((i & 0x1)==0)&&((j & 0x1)==0)){ i=i>>1; j=j>>1; c++; } //执行第二步 减数和差不相等则循环相减 while(i!=j){ if (i>j) i-=j; else j-=i; } gcd=i<<c; printf("%d %d\n",gcd,proc/gcd); } }
3、Stein算法
Stein算法有点类似于更相减损法,它是针对欧几里德算法在对大整数进行运算时,需要试商导致增加运算时间的缺陷而提出的改进算法。
思路:
如果An=0,Bn是最大公约数,算法结束
如果Bn=0,An是最大公约数,算法结束
如果An和Bn都是偶数,则An+1=An/2,Bn+1=Bn/2,Cn+1=Cn*2
如果An是偶数,Bn不是偶数,则An+1=An/2,Bn+1=Bn,Cn+1=Cn
如果Bn是偶数,An不是偶数,则Bn+1=Bn/2,An+1=An,Cn+1=Cn
如果An和Bn都不是偶数,则An+1=|An-Bn|/2,Bn+1=min(An,Bn),Cn+1=Cn
int gcd(int a, int b) { //找出最小的数b if (a<b) { int temp = a; a = b; b = temp; } //b为0 则a为公约数 if (b==0) return a; //同为偶数 则求a/2 和 b/2的公约数 if ((a&0x1)==0 && (b&0x1)==0) return 2*gcd(a>>1, b>>1); //a偶 b奇 则求a/2 和b的公约数 if ((a&0x1)==0 && (b&0x1)!=0) return gcd(a>>1, b); //a奇 b偶 则求a 和b/2的公约数 if ((a&0x1)!=0 && (b&0x1)==0) return gcd(a, b>>1); //a、b都不为偶数 则求(a-b)/2 和 b 的公约数 两个奇数相减为偶数 if ((a&0x1)!=0 && (b&0x1)!=0) return gcd((a-b)>>1, b); } main() { int i,j,m,proc,a; scanf("%d",&m); while(m--) { scanf("%d%d",&i,&j); proc=i*j; a=gcd(i,j); printf("%d %d\n",a,proc/a); } }
优化后
#include <stdio.h> int gcdcore(int a,int b) { if (a==0) return b; if (b==0) return a; while ((a & 0x1)==0) { a=a>>1; } if (a<b) { b=(b-a)>>1; return gcdcore(b,a); } else { a=(a-b)>>1; return gcdcore(a,b); } } int gcd(int a,int b) { int c=0; while (((a & 0x1)==0)&&(( b & 0x1 )==0)) { a=a>>1; b=b>>1; c++; } if ((a & 0x1) == 0) { a=a>>1; return gcdcore(a,b)<<c; } else { return gcdcore(b,a)<<c; } } //通过改善流程省去了低效的a,b交换,同时用while循环代替了过多的递归,以节约空间和时间。 //迭代过程化为子过程以减少不必要的判断 //子过程中只有减法运算后的值可能为偶数所以只需要对a判断是否为偶数 main() { int i,j,m,proc,a; scanf("%d",&m); while(m--) { scanf("%d%d",&i,&j); proc=i*j; a=gcd(i,j); printf("%d %d\n",a,proc/a); } }优化过的函数先进行预处理,通过一个while循环约掉所有2,递归部分交给gcdcore函数完成,减少了递归次数,从而提高了效率。
优点: Stein算法只有整数的移位和加减法 更适应程序。
复杂度: 对于大素数,Stein算法将更有优势。
相关文章推荐
- 浅谈装饰模式decorate
- 九度1514
- WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[中篇]
- 一篇文章读懂支付宝9.0改版背后的产品逻辑和战略布局
- ecshop模糊搜索分词插件 dede 开源插件
- android的DrawerLayout
- C# 抽象类
- Scripting.FileSystemObject对象
- Mysql几种索引类型的区别及适用情况
- 虚幻4 C++ 打LOG
- WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[上篇]
- 【Android测试】【第二节】ADB——无线模式
- 用imageNamed加载图片产生的问题
- java-集合下
- Nessus漏洞扫描教程之安装Nessus工具
- 悟空学Linux专栏----第17篇
- BM25 vs Lucene Default Similarity Comparing Precision and Recall
- linux c server and client 简单的通信
- Ubuntu14.04安装Tex
- 图片处理方法