数学问题-欧几里得算法扩展

欧几里得算法-计算a,b最大公约数

计算方法

1.当b≠0时:a=b,b=a%b;
2.当b=0时,最大公约数为a;

算法

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

扩展-计算ax+by=gcd(a,b)

方法(其中a,b是在不断变化的)

  1. 首先计算出gcd=gcd(a,b);
  2. a x 1 + b y 1 = g c d ax_{1}+by_{1}=gcd ax1+by1=gcd b x 2 + ( a % b ) y 2 = g c d bx_{2}+(a\%b)y_{2}=gcd bx2+(a%b)y2=gcd,所以 a x 1 + b y 1 = b x 2 + ( a % b ) y 2 ax_{1}+by_{1}=bx_{2}+(a\%b)y_{2} ax1+by1=bx2+(a%b)y2,又 a % b = a − ( a / b ) ∗ b a\%b=a-(a/b)*b a%b=a(a/b)b,所以整理得到 a x 1 + b y 1 = a y 2 + b ( x 2 − ( a / b ) y 2 ) ax_{1}+by_{1}=ay_{2}+b(x_{2}-(a/b)y_{2}) ax1+by1=ay2+b(x2(a/b)y2),所以 x 1 = y 2 , y 1 = x 2 − ( a / b ) ∗ y 2 x_{1}=y_{2},y_{1}=x_{2}-(a/b)*y_{2} x1=y2,y1=x2(a/b)y2;
  3. 这样通过递归计算就可以得到一组解 x , y x,y x,y,此时显然 a ∗ ( x + s 1 ) + b ∗ ( y − s 2 ) = g c d a*(x+s_{1})+b*(y-s_{2})=gcd a(x+s1)+b(ys2)=gcd,化简得到 s 1 / s 2 = b / a = ( b / g c d ) / ( a / g c d ) s_{1}/s_{2}=b/a=(b/gcd)/(a/gcd) s1/s2=b/a=(b/gcd)/(a/gcd),所以 x a l l = x + b / g c d ∗ k i , y a l l = y − a / g c d ∗ k i , i = 0 , 1 , 2 , 3 , . . . x_{all}=x+b/gcd*k_{i},y_{all}=y-a/gcd*k_{i},i=0,1,2,3,... xall=x+b/gcdki,yall=ya/gcdki,i=0,1,2,3,...,可以看出 x a l l , y a l l x_{all},y_{all} xallyall分别以 b / g c d , a / g c d b/gcd,a/gcd b/gcd,a/gcd为周期,所以最小的正整数 x = ( x % ( b / g c d ) + ( b / g c d ) ) % ( b / g c d ) x=(x\%(b/gcd)+(b/gcd))\%(b/gcd) x=(x%(b/gcd)+(b/gcd))%(b/gcd),(这里是为了保证x为正整数,因为等式右侧的 x x x可能为负数);

代码

int getgcd(int a,int b,int &x,int &y){//这里找出x,y与a和b的最大公约数
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int g = getgcd(b,a%b,x,y);//获得最大公约数
	//递归找到最初的x与y
	int temp=x;
	x=y;
	y=temp-(a/b)*y;
	return g;
}

进一步扩展-计算ax+by=c

方法

  1. 首先我们计算 a x + b y = g c d ( a , b ) = g c d ax+by=gcd(a,b)=gcd ax+by=gcd(a,b)=gcd x x x;
  2. 然后两边同时乘以 c / g c d c/gcd c/gcd a x ∗ ( b / g c d ) + b y ∗ ( b / g c d ) = g c d ∗ ( c / g c d ) ax*(b/gcd)+by*(b/gcd)=gcd*(c/gcd) ax(b/gcd)+by(b/gcd)=gcd(c/gcd),(注意到 c % g c d = = 0 c\%gcd==0 c%gcd==0才成立);
  3. 所以我们由上一个问题可以得到该问题的解 x a l l = x ∗ ( b / g c d ) + b / g c d ∗ k i , y a l l = y ∗ ( b / g c d ) − a / g c d ∗ k i , i = 0 , 1 , 2 , 3 , . . . x_{all}=x*(b/gcd)+b/gcd*k_{i},y_{all}=y*(b/gcd)-a/gcd*k_{i},i=0,1,2,3,... xall=x(b/gcd)+b/gcdki,yall=y(b/gcd)a/gcdki,i=0,1,2,3,...;

再次扩展-同余式计算

概念:

a与c模m同余:即(a-b)%m=0;可以写成:ax=c(mod m);

方法

  1. ( a x − m ) % c = 0 (ax-m)\%c=0 (axm)%c=0,可以转化为 a x + c k = m ax+ck=m ax+ck=m,这样就转化成为了上一个问题同样有 m / g c d ( a , m ) = 0 m/gcd(a,m)=0 m/gcd(a,m)=0。此时 x a l l = x + ( m / g c d ) ∗ k x_{all}=x+(m/gcd)*k xall=x+(m/gcd)k其中,k的取值只能在0,1,…,m-1中取,否则会被在这个范围内的数取代.

再次扩展-逆元

概念

若a*b=1(mod m),即 ( a ∗ b ) % m = 1 (a*b)\%m=1 (ab)%m=1,这样即是同余式中的余数1;这里注意要求gcd(a,m)=1,否则无解,因为此时c/gcd(a,m)=1/gcd(a,m),由第二个问题可得,必然要求gcd(a,m)=1.

扩展

当模m为素数时,所要求的a*b=1(mod m),已知a,且a≠0,则 b = a m − 1 b=a^{m-1} b=am1

你可能感兴趣的:(C++,数学基础,算法)