题解:AcWing 872 最大公约数
【题目来源】
AcWing:872 最大公约数 - AcWing题库
【题目描述】
给定 \(n\) 对正整数 \(a_i,b_i\),请你求出每对数的最大公约数。
【输入】
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数对 \(a_i,b_i\)。
【输出】
输出共 \(n\) 行,每行输出一个整数对的最大公约数。
【输入样例】
2
3 6
4 6
【输出样例】
3
2
【核心思想】
-
问题分析:给定 \(n\) 对正整数 \(a_i, b_i\),求每对数的最大公约数(GCD)。最大公约数是能够同时整除两个数的最大正整数。这是一个基础的数论问题,核心在于利用欧几里得算法(辗转相除法)高效求解两数的 GCD。
-
算法选择:
- 欧几里得算法(辗转相除法):基于核心定理 \(\gcd(a, b) = \gcd(b, a \bmod b)\),通过不断取余将问题规模缩小,直到余数为 \(0\) 时得到答案
- 递归实现:代码简洁,直接按照公式递归调用,终止条件为 \(b = 0\)
-
关键步骤:
- 读取输入:整数 \(n\),以及 \(n\) 对正整数 \((a_i, b_i)\)
- 定义 GCD 函数:
gcd(a, b):若 \(b = 0\) 则返回 \(a\),否则返回gcd(b, a % b)
- 处理每组数据:
- 输入 \(a, b\)
- 调用
gcd(a, b)计算最大公约数 - 输出结果
-
时间/空间复杂度:
- 时间复杂度:\(O(n \cdot \log(\min(a_i, b_i)))\)。欧几里得算法单次时间复杂度为 \(O(\log(\min(a, b)))\),处理 \(n\) 对数据乘以 \(n\)
- 空间复杂度:\(O(\log(\min(a_i, b_i)))\),递归栈深度,由欧几里得算法的迭代次数决定
-
欧几里得算法的核心思想:
- 核心定理:\(\gcd(a, b) = \gcd(b, a \bmod b)\)。若 \(d\) 是 \(a\) 和 \(b\) 的公约数,则 \(d\) 也是 \(b\) 和 \(a \bmod b\) 的公约数;反之亦然。因此两问题的最大公约数相同
- 规模递减:每次递归都将较大的数替换为两数相除的余数,余数严格小于除数,确保问题规模严格递减,最终必然在有限步内达到 \(b = 0\) 的终止条件
- 效率保证:对于斐波那契数对,欧几里得算法达到最坏情况,但即便如此迭代次数也仅为 \(O(\log(\min(a, b)))\),效率极高
- 扩展应用:GCD 是数论的基石,可直接用于计算最小公倍数(\(\text{lcm}(a, b) = a \times b / \gcd(a, b)\)),也是扩展欧几里得算法、中国剩余定理等高级算法的基础
- 适用于两数最大公约数、最小公倍数、分数约分、模逆元 existence 判断等问题
【算法标签】
欧几里得算法
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // 输入的计算次数
// 计算两个数的最大公约数(GCD)
int gcd(int a, int b)
{
// 递归终止条件:当b为0时,a即为最大公约数
// 否则递归计算gcd(b, a % b)
return b ? gcd(b, a % b) : a;
}
int main()
{
// 输入需要计算GCD的次数
cin >> n;
// 处理每组输入
while (n--)
{
int a, b;
cin >> a >> b; // 输入两个整数
// 计算并输出它们的最大公约数
cout << gcd(a, b) << endl;
}
return 0;
}
【运行结果】
2
3 6
3
4 6
2
浙公网安备 33010602011771号