扩展欧几里得extgcd

简单写一下最大公约数: 对一个整数a来说,如果存在x使得a % x = 0(a除x,除得的商正好是整数而没有余数),就说x是a的约数,比如12的约数有1, 2,3,4,6,12

那两个数的最大公约数就是两个数a,b的公共的约数中最大的那个,如6的约数有1,2,3,6,那么6和12的最大公约数就是6; 8的约数有1,2,4,8,那么8和12的最大

公约数就是4.多个数的扩展就不说了.用得多的就是两个数之间的:

typedef long long ll;

ll gcd(ll a, ll b) {
    if (b) return a;
    return gcd(b, a%b);
}//欢迎拿去用,这写法简洁,而且绝对正确!

进入主题,扩展欧几里得:

/*
 * (1) source: 求整数x,y使得ax+by=1
 * 推导:如果gcd(a,b)!=1,那么不妨设gcd(a,b)=k(k>1)则原式变成k(x*(a/k) + y*(b/k))=1,其中由于
 * k是a,b公约数,a/k,b/k依然是整数,可以相见,一个大于1的整数乘以另一个整数是不可能等于1的,
 * 回到刚才,我们可以知道要使ax+by=1 必须有gcd(a,b)=1**********(1)
 * (2)事实上,一定存在整数对(x,y)使得ax+by=gcd(a,b),如果另gcd(a,b)等于1,就可以导出过程(1)
 * 设int extgcd(int a, int b, int& x, int& y)是求解该方程的函数,返回值为gcd(a,b).和gcd的定义:
 * int gcd(int a, int b) {
 * 	if (!b) return a;
 * 	return gcd(b, a%b);
 * }
 * 一样,我们可以递归地定义extgcd.
 * 假设已经求得了: bx'+(a%b)y'=gcd(a,b)的整数解x'和y'.再将a%b=a-(a/b)*b代入后就得到:
 * ay'+b(x'-(a/b)*y')=gcd(a,b)
 * 而当b=0时则有a*1+b*0=a=gcd(a,b)
 * 将上述过程转化成代码就是:
 * int extgcd(int a, int b, int& x, int& y) {
 * 	int d = a;
 * 	if (b != 0) {
 * 		d = extgcd(b, a % b, y, x);
 * 		y -= (a / b) * x;
 * 	} else {
 * 		x = 1; y = 0;
 * 	}
 * 	return d;
 * }
 * by. *花式*小冬摘自<<挑战程序设计竞赛>>
 */
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;

/****************************************/
typedef long long ll;
const int MAX = 7401;

/* ax + by = gcd(a,b) */
ll extgcd(int a, int b, int& x, int& y) {
	int d = a;
	if (b) {// --> if (b != 0) {
		d = extgcd(b, a%b, y, x);
		y -= (a/b) * x;
	} else {
		x = 1; y = 0;
	}
	return d;
}

int main() {
	int a, b, x, y;
	srand(unsigned(time(0)));//用系统当前时间为随机数种子
	while (!cin.eof()) {
		a = rand()%MAX;
		b = rand()%MAX;//随机生成a,b,其实我们完全可以筛选掉负数,但是没关系,这里看看就好了
		int _gcd = extgcd(a, b, x, y);
		printf("(%d, %d) matchs %d*%d + %d*%d = %d\n", x, y, a, x, b, y, _gcd);
		puts("......................................");
		cin.clear();
		cin.get();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值