拓展欧几里得

相信大家都知道欧几里得法(辗转相除)求两个数的 g c d ( 最大公因数 ) gcd(最大公因数) gcd(最大公因数)
根据这个算法的公式是

欧几里得

g c d ( a , b ) = g c d ( b , a gcd(a,b)=gcd(b,a gcd(a,b)=gcd(b,a% b ) b) b)

证明:
若r = a%b,则a可以表示成 r = a − k ∗ b , ( k = a / b ) r=a -k*b, (k=a/b) r=akb,(k=a/b)
假设 d d d a , b a,b a,b的一个公约数,
则有a%d=0, b%d=0,
a = x ∗ d a = x*d a=xd , b = y ∗ d b = y*d b=yd, x , y x,y x,y为整数
r = a − k ∗ b = x ∗ d − k ∗ y ∗ d = ( x − k ∗ y ) ∗ d r = a - k*b = x*d-k*y*d = (x-k*y)*d r=akb=xdkyd=(xky)d
因为 x − k ∗ y x-k*y xky是整数,所以 r r r d d d的倍数, r r%d=0 r
因此 d d d是(b,a % b)的公约数
证毕


拓展欧几里得

实现

解一组整数 x , y , 使得 a ∗ x + b ∗ y = G c d ( a , b ) 解一组整数x,y,使得a*x+b*y = Gcd(a,b) 解一组整数x,y,使得ax+by=Gcd(a,b)

g c d ( a , b ) = a x + b y gcd(a,b)=ax+by gcd(a,b)=ax+by

g c d ( b , a   m o d   b ) = b x ′ + ( a − a / b ∗ b ) y ′ gcd(b, a  mod   b)=bx'+(a-a/b*b)y' gcd(b,a mod b)=bx+(aa/bb)y
a x + b y = b x ′ + ( a − a / b ∗ b ) y ′ ax+by=bx'+(a-a/b*b)y' ax+by=bx+(aa/bb)y
整理可得 : x = y ′ , y = x ′ − ( a / b ) y ′ x=y',y=x'−(a/b)y' x=y,y=x(a/b)y
然后对于这个式子就可以递归求解了,显然在 b = 0 b=0 b=0 x = 1 , y = 0 x=1,y=0 x=1,y=0,然后就可以返回地去求了

应用拓欧(关于 a x + b y = c ax+by=c ax+by=c

判定是否有解

从上可知,当 c = = g c d ( a , b ) ∗ k c==gcd(a,b)*k c==gcd(a,b)k,那么就一定有解,反之就无解

求通解

我们先可以就特殊解,因为C是gcd(a,b)的倍数于是,原来的方程就可以传化为
a x + b y = c    = > a x / d + b y / d = g c d ( a , b ) ax+by=c   => ax/d+by/d=gcd(a,b) ax+by=c  =>ax/d+by/d=gcd(a,b)就在原来的答案上/d就好

原方程的解有无限多组,因为满足下面式子:
a ∗ ( x + k ∗ b ) + b ∗ ( y − k ∗ a ) = c a*(x+k*b)+b*(y-k*a)=c a(x+kb)+b(yka)=c (化简之后一些可以抵消) k k k为整数
于是我们得到 a x + b y = c ax+by=c ax+by=c的通解:
x = x ′ ∗ c / d + k ∗ b / d x=x'*c/d+k*b/d x=xc/d+kb/d
y = y ′ ∗ c / d − k ∗ a / d y=y'*c/d-k*a/d y=yc/dka/d

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
template <typename T>
inline void _read(T& x){
	char ch=getchar();bool sign=true;
	while(!isdigit(ch)){if(ch=='-')sign=false;ch=getchar();}
	for(x=0;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+ch-'0';
	if(!sign)x=-x;
}
int x,y;
int extended_gcd(int a, int b) { //ax+by=gcd(a,b)
 	   int r, tmp;
	   if (b==0) {  x = 1;  y = 0;  return a; } 
	   r = extended_gcd(b, a % b); 
 	   tmp=x; x=y;   y =tmp - a / b * y;
       return r; 
} 

int main(){
	int a,b,c;
	cin>>a>>b>>c; //求ax+by=c的一组解 
	int d=extended_gcd(a,b);
	if(c%d!=0){
		puts("-1");
		return 0;
	}
	else {
		cout<<x*c/d<<" "<<y*c/d<<endl;//输出一组解 
		for(int k=1;k<=10;k++){
			int x1,y1;
			x1=x*c/d+k*b/d; //通解 
			y1=y*c/d-k*a/d;
			cout<<x1<<" "<<y1<<endl;
		}
	}
}

应用拓欧(解模线性方程)

a ≡ b (mod n)的含义是a和b关于模n同余,即a mod n==b mod n
a ≡ b (mod n)的充要条件是a-b是n的整数倍
这样,ax ≡ b (mod n)可以解释成:ax-b是n的整数倍,设这个倍数为y,
则ax-b=ny,移项得ax-ny=b,这恰好是一个二元一次不定方程。
用扩欧就可以解决。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值