题目
已知a,b是整数,求ax + by=1的一组整数解。
分析
思考过程如下:
- 先考虑一种最简单的情况,假设b为0,则a = 1,x = 1,y可以取任意值。
- 如果系数a和b的最大公约数大于1,那么这个方程一定没有整数解。
- 联想到辗转相除法求a,b两个数的最大公约数时,如果最大公约数为1,则无论a,b的初始值为多少当迭代到最后一轮的时候都有a = 1,b = 0,恰好与这个方程最简单的情况相同。
- 假设递归过程两个相邻的调用级别为n-1与n,对应的参数分别为(a,b)与(b,a%b),用数学归纳法证明,假设第n层有整数解x,y满足b * x + (a % b) * y = 1,只需要把b * x + (a % b) * y = 1转化成以a,b为系数的形式,即a * y + b(x - k * y)=1.因为x,y都是整数,所以y,(x - k * y)也是整数,所以第n-1层也有整数解并且为y,(x-k*y)。这样就得到了求整数解的递推公式,即:从(x,y)到(y,(x - k * y)),初始x=1,y为任意整数。(k为第n层a与b的商)
- 求解整数解问题就是利用递归辗转相除法求最大公约数的正向过程中每一层计算出的k,并且在回溯的过程中逐层利用这个k值。
代码如下
#include<stdio.h>
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int ex_gcd(int a, int b, int *x, int *y) {
if (!b) {
*x = 1;
*y = 0;
return a;
}
int xx, yy, ret = ex_gcd(b, a % b, &xx, &yy);
printf("a = %d, b = %d, ret = %d\n", a, b, ret);
*x = yy;
*y = xx - a / b * yy;
return ret;
}
int main() {
int a, b, x, y;
while (~scanf("%d%d", &a, &b)) {
int ret = ex_gcd(a, b, &x, &y);
printf("gcd(%d,%d) = %d\n", a, b, ret);
printf("%d * %d + %d * %d = %d\n", a, x, b, y, ret);
}
return 0;
}