【C++ 基础数论】最大公约数 & 最小公倍数

最大公约数

约数:如果 a 可以整除 b,则 a 为 b 的约数, b a \frac{b}{a} ab 也是 b 的约数,约数也叫因数。

试除法求约数

我们可以用上一章讲到的判断质数的方法,这里只需要判断能否整除,非常简单

参考上一篇文章质数判断

代码如下:

for(int i = 1; i <= n/i; i++){
	if(n % i == 0) cout<<i<<" "<<n/i<<endl;//i 与 n/i 都是因数
}

欧几里得算法(辗转相除法)

两个数的最大公约数简写为 gcd(a, b),即两个数的公共因数中最大的那个数。

那么如何求两个数的最大公约数呢 ?
这种算法的核心内容是 gcd(a, b) = gcd(b, a%b)

算法步骤

给定两非负整数 a, b (不得同时为0),重复以下操作:

  1. 用 a 除以 b , 得到余数 r
  2. 将 a 替换为 b , b 替换为 r

当某次余数 r = 0 时, 此时的 a 即为原两数的最大公约数

证明
GCD不变性

假设 d 为 a, b 的公约数,存在唯一的一个 商q 与 余数r

使
a = b ∗ q + r a = b\ast q + r a=bq+r


a = k 1 ∗ d a = k_1 \ast d a=k1d b = k 2 ∗ d b = k_2 \ast d b=k2d


d ∗ k 1 = ( d ∗ k 2 ) ∗ q + r d \ast k_1 = ( d \ast k_2 ) \ast q+ r dk1=(dk2)q+r
整理后
r = d ∗ ( k 1 − k 2 ∗ q ) r = d \ast ( k_1 - k_2 \ast q ) r=d(k1k2q)

所以 d 必须能整除 a, b, 同时也能整除余数 r ;

反过来,若 d = gcd(b , r), 则 d 也能整除 a

因此,gcd(a, b) = gcd(b, r), 每一步替换后, GCD保持不变

严格递减性

由于每次计算的 r 满足 0 ≤ \leq r < b, 余数严格递减, 最终必然在有限步内达到 r = 0

终止条件

当余数 r = 0 时, gcd(a, 0) = a,此时 a 即为原两数的GCD

代码
int gcd(int a, int b){
	if(b == 0) return a;
	return gcd(b, a%b);
}

最小公倍数( lcm(A, B) )

公式

l c m ( A , B ) = ( A ∗ B ) / g c d ( A , B ) lcm(A, B) = (A \ast B ) / gcd(A, B) lcm(A,B)=(AB)/gcd(A,B)

证明

对于两个数 A, B,我们设 A = a ∗ k A = a \ast k A=ak, B = b ∗ k B = b \ast k B=bk (k 为 gcd(A, B) )

因为 A ∗ B = A ∗ B A \ast B = A\ast B AB=AB
带入, 得:
A ∗ ( b ∗ k ) = ( a ∗ k ) ∗ B A \ast ( b \ast k ) = ( a \ast k ) \ast B A(bk)=(ak)B

化简:
A ∗ b = a ∗ B A \ast b = a \ast B Ab=aB

等式两边就是我们要找的 lcm(A, B)

易推得 l c m ( A , B ) = ( A ∗ B ) / g c d ( A , B ) lcm(A, B) = (A \ast B ) / gcd(A, B) lcm(A,B)=(AB)/gcd(A,B)

代码很简单, 这里就不放了

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QuantumStack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值