裴蜀等式(扩展欧几里得)

    裴蜀等式

对任何整数a,b,及他们的最大公约数d,ax+by=m有整数解当且仅当m是d的倍数时。

裴蜀等式有解时必然有很多解,每一组解(x,y)称为裴蜀数

ax+by=gcd(a,b)

当gcd运行到最后,可以得出b==0,这样才返回a是最大公约数,此时可以得到x=1,y=0。我们通过递推得出原来的a,b的解x,y。

当前状态为:ax+by=gcd(a,b)      (1)

下一个状态:bx_{1}+(a.mod.b)y_{1}=gcd(b,a.mod.b)   (2)

因为gcd(a,b)=gcd(b,a mod b),且a mod b=a-(a/b)*b

所以                        gcd(a,b)=gcd(b,a.mod b)          

                                               =bx_{1}+(a-(a/b)*b)*y_{1}

                                               =ay_{1}+b(x_{1}-a/b*y_{1})       (3)

所以得出:           ax+by=ay_{1}+b(x_{1}-a/b*y_{1})       (4)

x1,y1是下一个状态的量,x,y是当前状态的量。

而且       x=y1.

              y=x1-a/b*y1.

代码如下:

package _数论;

public class _裴蜀等式 {
	
	static long x,y;
	static long ex_gcd(long a,long b) {

		if(b==0) {
			x=1;
			y=0;
			return a;
		}
		long res=ex_gcd(b,a%b);//求下一次的exgcd
		
		//之前求出的是X1,y1
		long x1=x;
		x=y;
		y=x1-(a/b)*y;
		return res;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		//12x+42y=6;
		long t=ex_gcd(12,42);
		System.out.println("x: "+x+"  y: "+y+" gcd: "+t);
	}

}

我们可以得到其中一个解为 x,y. 

假设新的解为 x+s1,y-s2, 代入公式有 a(x+s1)+b(y+s2)=gcd.    而ax+by=gcd。所以 a*s1=b*s2.

a与b互质,最大公因数为gcd,所以    \frac{s1}{s2}=\frac{a}{b}=\frac{a/gcd}{b/gcd}   ,s1,s2的最小取值为 a/gcd ,b/gcd.

所以 ax+by=gcd 的全部解为  \\x*=x+\frac{b}{gcd}*k\\y*=y-\frac{a}{gcd}*k  (k为任意整数)

 ax+by=c (c为任意数)

ax0+by0=gcd 的一组解为(x0,y0),对两边同时乘以 c/gcd ,得 \frac{a*c*x_{0}}{gcd}+\frac{b*c*y_{0}}{gcd}=c,显然,这样做的充要条件是c%gcd==0。那么现在 ax+by=c的一组解为\left \{ \frac{cx_{0}}{gcd},\frac{cy_{0}}{gcd} \right \}

令x*=x+s1,y*=y-s2,和上面一样可以得到:\\x*=\frac{c*x_{0}}{gcd}+\frac{b}{gcd}*k\\y*=\frac{c*y_{0}}{gcd}-\frac{a}{gcd}*k(k为任意整数)

ax≡c ( mod m)

同余式 a≡c (mod m) 的含义是  a mod m = c mod m。即(a-c)%m=0.

对于 ax≡c (mod m) ,得 (ax-c)%m=0。因此存在一个整数-y,使得  ax-c= -my。移项得  ax+my=c 

可求得一个解 (x0,y0),当 c%gcd(a,m)=0时。(x,y)=\left \{ \frac{cx_{0}}{gcd},\frac{cy_{0}}{gcd} \right \}.

                                              最终解为 :         \\x*=\frac{c*x_{0}}{gcd}+\frac{m}{gcd}*k\\y*=\frac{c*y_{0}}{gcd}-\frac{a}{gcd}*k

结论:设a,c,m为整数,m>=1:

1.若 c%gcd(a,m) !=0 .   同余式方程无解

2.若等于0,  则方程有 gcd(a,m) 个不同的解.

逆元的求解及 (b/a)%m的计算

逆元:如果两个整数模m等于1,就称他们互为m 的逆元。例如 ab≡1 (mod m)  =====>  a≡(1/b) (mod m)  =====>b≡(1/a) (mod m).

对乘法来说,(b*a)%m=((b%m)*(a%m))%m。但是对于除法来说,(b/a)%m却不等于 ((b%m)/(a%m))%m.也不等于((b%m)/a)%m.

这时候就需要逆元来计算 (b/a)%m.“ 除以一个数再取模等同于乘以这个数的逆元再取模 "

通过寻找 a 的逆元x,可以将上式变为 (b*x)%m;  求a的逆元就是 求ax≡1(mod m).如果1%gcd=1,则有唯一解。

代码附上:


import java.util.Scanner;

//time:2019年9月20日下午10:49:21

public class 扩展欧几里得 {

	static int gcd(int a, int b) {
		if (b == 0)
			return a;
		return gcd(b, a % b);
	}

	/**
	 * 扩展欧几里得:求ax+by=gcd(a,b)的解 假设解为 x,y 那么全部解为 x*=x+b/gcd*k y*=y+a/gcd*k
	 * 
	 * @author:ywl
	 * @Description:
	 * @return:
	 */
	static int x = 0, y = 0;

	static int ex_gcd(int a, int b) {
		if (b == 0) {
			x = 1;
			y = 0;
			return a;
		}
		int g = ex_gcd(b, a % b);// 递归计算
		int temp = x;
		x = y;// 更新x
		y = temp - a / b * y;// 更新y
		return g;
	}

	/**
	 * 欧几里得的应用:求解ax+by=gcd (c为任意数) 假设解为 x,y 那么ax+by=c全部解为 x*=cx0/gcd+b/gcd*k
	 * y*=cy0/gcd-a/gcd*k
	 * 
	 * @author:ywl
	 * @Description:
	 * @return:
	 */

	/**
	 * 同余式的求解 对于 ax≡c (mod m) ,得 (ax-c)%m=0。因此存在一个整数-y,使得  ax-c= -my。移项得  ax+my=c 
	 * 
	 * 可求得一个解 (x0,y0),当 c%gcd(a,m)=0时。
	 * 
	 * @author:ywl
	 * @Description:
	 * @return:
	 */

	/**
	 * 逆元的求解
	 * 
	 * @author:ywl
	 * @Description:
	 * @return:
	 */
	static int inverse(int a, int m) {
		int gcd = ex_gcd(a, m);
		if (1 % gcd == 0) {
			// 求出在m范围内的x,也防止负数
			return (x % m + m) % m;
		}
		return -1;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		int gcd = ex_gcd(a, b);
		System.out.println("gcd: " + gcd);
		System.out.println("---------求ax+by=gcd(a,b)--------------");
		for (int k = 0; k < 5; k++) {
			int xx = x + b / gcd * k;
			int yy = y - a / gcd * k;
			int sum = xx * a + yy * b;
			System.out.println("x: " + xx + " y:" + yy + " " + sum);
		}
		int c = sc.nextInt();
		System.out.println("--------求ax+by=c-----------");

		for (int k = 0; k < 5; k++) {
			int xx = c * x / gcd + b / gcd * k;
			int yy = c * y / gcd - a / gcd * k;
			int sum = a * xx + b * yy;
			System.out.println("x: " + xx + " y: " + yy + " " + sum);
		}
		System.out.println("求同余式");
		int a2 = sc.nextInt();
		int c2 = sc.nextInt();
		int m2 = sc.nextInt();
		// 求x
		int gcd2 = ex_gcd(a2, m2);
		for (int k = 0; k < 5; k++) {
			int t1 = c * x / gcd2;
			int t2 = c * y / gcd2;
			int xx = t1 + m2 / gcd2 * k;
//			int yy = t2 - a / gcd * k;
			System.out.println(xx % m2);
		}
	}

}

 

发布了133 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41921315/article/details/88620174