文章汇总归纳整理于:算法竞赛学习之路[Java版]
这里不采用公式定理证明的方法进行讲解,算是讲解欧几里得算法(GCD, 辗转相除法)求解最大公约数的过程吧
以求 104 50 的最大公约数为例
欧几里得算法(GCD, 辗转相除法)求解过程讲解
- 求两个数 a b 的最大公约数,这个最大公约数只会出现在 1 到 两个数中较小的数 的这个范围内,即最大公约数∈[ 1, min(a, b) ]
- 因为两个数的最大公约数必须是两个数共同拥有的因子,所以这个最大公约数不能大于两个数中的其中任何一个数,即最大公约数 ≤ min(a, b),又因为 1 是任何数的约数,所以最大公约数∈[ 1, min(a, b) ]
- 由于要求最大的公约数,且每个数本身都是自己的最大约数,所以在辗转相除法求解最大公约数的过程中,每次取 min(a, b) 作为本次两个数的约数进行试探
- 104 / 50 = 2 ······ 4
- 此时 104 / 50,除不尽,即应该缩小除数,两个数的最大公约数小于 50,由于 50 * 2 + 4 = 104,被除数减去余数剩余的部分 100 一定可以被 50 除尽,能把 50 除尽的数也一定可以将 100 除尽,而要求 104 的约数,则需要满足所求得的约数应当也能将余数 4 除尽,于是求 104 50 的最大公约数变为求 50 4 的最大公约数
- 根据上述的讲解,50 4 的最大公约数只可能出现在 [ 1, 4 ] 这个区间中,所以取除数为 4 进行试探,判断 4 是否可以成为 50 4 的最大公约数,如果可以,4 也是104 50 的最大公约数
- 50 / 4 = 12 ······ 2
- 由于结果存在余数,所以还需要缩小除数,即两个数的最大公约数小于 4,根据上述的讲解,接下来,最大公约数只可能出现在 [1, 2] 这个区间中,取除数为 2 进行试探
- 4 / 2 = 2
- 此时可以除尽,不存在余数,所以 2 为 4 2 的最大公约数,能将 4 除尽,且可以将 50 / 4 的余数除尽,所以 2 为 50 4 的最大公约数(50 = 4 * 12 + 2),能将 50 除尽,也能将 104 / 50 的余数除尽,所以 2 为 104 50 的最大公约数(104 = 50 * 2 + 4)
- 由此,可得 104 50 的最大公约数为 2
欧几里得算法(GCD, 辗转相除法)代码实现
以 P1888 三角函数 为例,进行欧几里得算法(GCD, 辗转相除法)的代码实现
// package GCD; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int a = sc.nextInt(); int b = sc.nextInt(); int c = sc.nextInt(); // 三个数 a b c 从小到大进行排列 if (a > b) { int t = a; a = b; b = t; } if (a > c) { int t = a; a = c; c = t; } if (b > c) { int t = b; b = c; c = t; } // 计算较小锐角的正弦值 // 较小锐角的正弦值 = 最小的边长 / 最大的边长 // 由于结果要约分,所以要求出两个数的最大公约数 int gcd = gcd(a, c); // 求出两个数的最大公约数 // 输出结果 System.out.println((a / gcd) + "/" + (c / gcd)); } static int gcd(int a, int b) { while (a % b != 0) { // 如果两数相除存在余数,继续进行辗转相除法 int remain = a % b; // 余数 a = b; // 原先的除数变为被除数 b = remain; // 余数变为除数 } // 最终最大公约数在除数的位置(退出循环的条件为两数相除余数为0) return b; // 返回最大公约数 } }