数论及其应用——欧几里得算法

欧几里得是数论当中最基本的定理,以其为基础的拓展欧几里得算法在解决同余方程、求模逆元等问题。

首先来介绍几个概念,数论当中一些基本的概念其实在小学就学过,但是很长一段时间并没有用到它们,因此这里再拿出来温习一下。

我们常常用a|b来表示b能够整除a(b > a),即b/a是整数,但是“|”在使用的过程中容易和绝对值、几何定义符、条件概率混淆,所以,这里我们用a\b来表示a能够整除b。

约数:如果b\a,则称b是a的约数。

倍数:如果b\a,则称a是b的倍数。

最大公约数:gcd(a,b) = max{k | k\a 且k\b}。

最小公倍数:lcm(a,b) = min{k | k>0 , a\k 且b\k}

那么现在我们面临一个重要的问题,给出一系列数字,我们想要通过一个程序得到这些数字的最大公约数或者最小公倍数, 应该怎么做呢?

容易想到穷举,当然,容易想到的代价是牺牲大量的时间,我们需要用更好的思维去简化这个过程。

计算最大公约数的方法:欧几里得算法.

n>m,gcd(m,n) = gcd(n % m, m) , gcd(0,n) = n.

证明:

n = qm + r,r>0。
  我们假设存在这样一个d,它是m、n的公因子,即d\a 且 d\b。

可以看到r = n - qm ,假如c = xa + yb,且d\a,d\b,那么d\c。这里是同样道理,所以d\r,加上之前的d\b,定理成立.

基于这个结论,我们在求解gcd(m,n)(n > m)的时候,可以转而去求gcd(n % m , m).

求gcd(n % m , m)的时候,可以转而去求gcd(m%(n%m) , n%m)

……

这就形成了一个递归性质的求解过程,可能在说这个递归的流程你就会质疑,上面的证明过程我们给出的公因子相同,但是如何保证其是最大公因子(最大公约数)呢?想象一下这个递归过程,如果保证了递归的最后一层得到的公因子d是最大公因数,那么最终我们就会返回一个最大公约数。

那么现在我们要解决的一个主要问题变成了:递归的最底层是什么呢?或者说,递推到什么程度开始“归”呢?想象一下,递推下去的终点,gcd(a,b)的a、b中必然有一个数是0,然后用我们在定理中定义的:gcd(a,0) = a.a其实就是整个递归过程中的解,这保证了递归过程中传递的约数一直是最大公约数。

而在设计递归程序的时候,为了得到返回值(即上一段的a),我们规定gcd(a,b)函数a>b,这样返回结果即为:gcd(a,0),返回a.

参考代码如下:

#include<cstdlib>

#include<iostream>

using namespace std;

long long gcd(int a , int b)

{

     if(b == 0)

          return a;

     else  return gcd(b , a%b);

}
时间: 2024-10-24 15:30:52

数论及其应用——欧几里得算法的相关文章

数论初步——扩展欧几里得算法

具体内容见紫书p313-p314 一.扩展欧几里得算法 思想:找出一对整数(x,y),使得ax+by=gcd(a,b) 举例:当"a=6,b=15"时,gcd(6,15)=3,故可以得到解"x=3,y=-1",当然还有其他解"x=-2,y=1". 程序: /* 扩展欧几里得算法 */ void gcd(int a, int b, int& d, int& x, int& y) { if(b == 0){ //边界,因为 a

【数论】扩展欧几里得算法

扩展欧几里得     上回刚写完欧几里得,那现在还有一个东西叫拓展欧几里得:     扩展欧几里得法是一个在求解同余方程等问题上的一个很好的方法,其具体功能如下:     在已知(a,b)时,求解一组(p,q)使得p*a+q*b=GCD(a,b)          首先,根据数论中的原理,解一定是存在的.     我们可以设a对于GCD(a,b)的倍数是k,b对于GCD(a,b)的倍数是l     那么p*(GCD(a,b)*k)+q*(GCD(a,b)*l)=GCD(a,b)     可以推出

数论,类欧几里得算法

类欧几里得部分转载自不来也不去的一只失忆蝴蝶.%%%

数论杂谈——欧几里得算法及扩展欧几里得

数学是oi的重要基础,所以说数论在oi中占据了非常重要的地位,因此,学好数学,对于一个oier来说也是非常重要的. oi中的数学,其实也就和数竞并没有什么区别. 欧几里得法辗转相除法求最大公约数 我们可以证明gcd(a,b)=gcd(b,a%b),也就是我国古代数学智慧的结晶,更相损减术.并且一直递归下去,直到b的值为零,最大公约数值即为a.在这里就不给出详细证明了,大家可以代几个数据去验证它一下.谁叫我数学太菜. 代码如下 int GCD(int a,int b) { if(!b) { ret

POJ 1061 青蛙绕地球约会-数论-(解一元一次同余方程+扩展欧几里得算法)

题意:两只青蛙同向跳,起点是x,y,每次分别跳m,n米,地球周长是L,求最少跳几次相遇. 分析: 把式子写好就发现是一个一元一次同余方程.用扩展欧几里得算法来求.这题很基本得会. 代码: #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<queue> #define INF 100000

POJ 2115 for求循环次数-数论-(同余方程+扩展欧几里得算法)

题意:给定for循环的初始值,结束值和增量,还有一个模,求最少的循环次数. 分析: 读完题后应该就知道是一个同余的概念,所以就是解一个一元一次同余方程,像上题一样用扩展欧几里得算法.这题的trick点是k最大为32,那么2^32超出了int,要用long long,所以在1<<k时要这样做:1LL<<k,不然就WA了. 代码: #include<iostream> #include<cstdio> #include<algorithm> #inc

数论专题---除法表达式之高精度运算,扩展欧几里得算法

[题意描述] 给定这样一个表达式:X1/X2/X3/·····/Xk,其中Xi是正整数.除法表达式应到按照从左到右的顺序求和.但在表达式中嵌入括号可以改变计算顺序.输入表达式,判断是否可以通过加括号使得表达式最后的值为整数. [分析] 表达式可以写成E=(X1·X3·····Xk)/X2:(X1一定在分子位置,X2一定在分母位置,其它任意) 问题变为E是否为整数. 对于大数相乘,我们可以采用两种方法避免数据溢出: 1.采用素数的唯一分解定理:存储可能存在素数的个数(如何存储,用一个数组就行) 2

数论初步-欧几里得算法

1 int judge(int* X) { 2 X[2] /= gcd(X[2], X[1]); 3 for(int i = 3; i <= k; i++) X[2] /= gcd(X[i], X[2]); 4 return X[2] == 1; 5 } 这个算法称为欧几里得算法.不会溢出,因为gcd函数的递归层数不超过4.785lgN + 1.6723,其中N=max{a,b}. 让gcd递归层数最多的是gcd(Fn,Fn-1).利用gcd还可以求出两个整数a和b的最小公倍数lcm(a,b).

总结——数论:欧几里得算法&amp;扩展欧几里得证明

一 欧几里得辗转相除法算法 设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),又因 r = a mod b,所以 gcd(a,b)=gcd(b,a mod b). 证明:①证明充分性. 设 d 为 a,b 的公约数,记作 d|a , d|b ,即a和b都可以被d整除 又因 r=a-kb , 两边同时除以d,r/d=a/d-kb/d=m,由等式右边可知m为整数, d|r , 即 d 是 (b,a mod b)的公约数, ②证明必要性 设 d 为 b, a mod b