欧几里得与扩展欧几里得算法

一、欧几里得算法

1.简介

欧几里得算法又称辗转相除法,这种算法我们在高中的数学书上都有所了解,这种算法的用途是旨在求两个数的最大公约数(英文缩写为gcd)。

2.算法分析

例如,如果我们要求去寻找12和16的最大公约数,我们可以这样操作:

第一步:16 mod 12 = 4;

第二步:12 mod 4 = 0;

第三步:4 mod 0,这时候b==0的时候,a==4就是我们12和16的最大公约数。

3.代码分析

int gcd(int a,int b)
{
    return !b?a:gcd(b,a%b);

}

代码的长度其实很简单,就是判断b是否为0,如果为0,返回a,否则递归寻找。

二、扩展欧几里得算法

1.简介

何为扩展欧几里得算法?扩展欧几里得算法顾名思义就是欧几里得算法的扩展。这个算法旨解决一个问题:求gif.latex?ax%20+%20by%20%3D%20gcd%28a%2Cb%29,其中a,b为常数,gcd(a,b)为a,b的最小公倍数 的整数解(可以拥有多个整数解)。

2.算法分析

求解特殊情况:gif.latex?%28ax%20+%20by%20%3D%20gcd%28a%2Cb%29%29

首先我们要知道裴蜀定理,就是gif.latex?ax%20+%20by%20%3D%20gcd%28a%2Cb%29一定会有整数解。

由欧几里得算法可知gif.latex?gcd%28a%2Cb%29%20%3D%20gcd%28b%2Ca%25b%29;......①

若b=0时,则gif.latex?ax%20%3D%20a,x=1,令y=0;

若a≠0时,则gif.latex?ax%20+%20by%20%3D%20gcd%28a%2Cb%29成立;......②

gif.latex?b%7Bx%7D%27%20+%20%28a%25b%29%7By%7D%27%20%3D%20gcd%28b%2Ca%25b%29

b%29*b%29%7By%7D%27%20%3D%20gcd%28b%2Ca%25b%29......③

将①②③联立得b%20%5Cright%20%5Crfloor*%7By%7D%27

这样,我们可以用递归的形式来求得x和y的值。

void exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;
        y=0;

        return;
    }
    exgcd(b,a%b,y,x);
    y=y-a/b*x;
}

求解一般情况:(gif.latex?ax%20+%20by%20%3D%20d)

由裴蜀定理可知,若gif.latex?ax%20+%20by%20%3D%20d有解,则必然满足gif.latex?gcd%28a%2Cb%29%7Cb

gif.latex?c%3Dgcd%28a%2Cb%29,则我们可以先求gif.latex?a%7Bx%7D%27%20+%20b%7By%7D%27%20%3D%20c的解,然后得到x,y的值c

其中x,y都是特解

非齐次通解=非齐次的特解+齐次通解则,我们只需要求gif.latex?ax%20+%20by%20%3D%200通解

gif.latex?x_%7B0%7D%3D-kb%2Cy_%7B0%7D%3Dka,带入得到gif.latex?x%3Dx_%7B0%7D+%7Bx%7D%27%2Cy%3Dy_%7B0%7D+%7By%7D%27

3.代码分析

例题引入:AcWing 878. 线性同余方程

例题分析:gif.latex?%5Cbg_white%20a*x%20%5Cequiv%20b%28%25m%29可以化为gif.latex?%5Csmall%20a*x%20-%20b%20%3D%20k*m%2C%28k%5Cin%20%5Cmathbb%7BZ%7D%29

即可以化为gif.latex?%5Csmall%20a%20*%20x%20+%20k*m%20%3D%20b%2C%28k%5Cin%20%5Cmathbb%7BZ%7D%29//因为k仅仅只是个常数,所以可以不变号

这样就是求x和k的整数解的题了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
void exgcd(long long a,long long b,long long &x,long long &y){
	if(b==0){
		x=1;
		y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y=y-a/b*x;
}
long long gcd(long long a,long long b){
	return !b?a:gcd(b,a%b);
}
int main(){
	long long t;
	cin>>t;
	while(t--){
		long long a,b,m;
		cin>>a>>b>>m;
		long long sum=gcd(a,m);
		if(b%sum!=0){
			cout<<"impossible"<<endl;
		}
		else{
			long long x=0,y=0;
			exgcd(a,m,x,y);
			cout<<x%m*(b/sum)%m<<endl;//直接乘以b/gcd(a,b)即可
		}
	}
	return 0;
}

关于求解最小正整数解的时候,只需要 x=(x%t+t)%t,t=b/gcd(a,b);

同理,y=(y%t+t)%t,t=a/gcd(a,b);

posted @   YutaoJiang  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示