线性同余方程

// 定理一:对于方程a * x + b * y = c 有整数解 x, y 可以转化为a * x 三 c(mod b)
// 根据扩展欧几里得算法可知,a * x0 + b * y0 = GCD( a, b)一定有解, 此时将方程左右同时出去GCD( a, b)在乘上c
// 方程就转化成了a * x0 * c / GCD( a, b) + b * y0 * c / GCD( a, b) = c 已经可以说明 c / GCD( a, b)是整数了 
// 可以知道 b * y mod b == 0,则 c mod b = (a * x + b * y) mod b 就等于a * x mod b
// 所以上面两个方程是等价的, 而同理可知 b * y 三 c (mod a) 此时说明 c 一定是a 与 b是最大公约数的倍数(包括 0倍)
// 定理二:若GCD( a, b) = 1, 且x0, y0为a * x0 + b * y0 = c 的一组解,那么x = x0 + b * t, y = y0 + a * t 都是原来方程的解
// (t 是整数). 所以能从此处知道方程存在的最小整数解为 t = b / GCD( a, b), x = ((x % t) + t) % t (此处加t 是为了防止取模后为负数)
// 先来扩展欧几里得算法
// 过程证明
// 扩展欧几里得算法
// 方程形式 a * x0 + b * y0 = GCD( a, b);
// 需要求解出 x0与y0
// 现在考虑最后状态 是 a` * 1 + 0 * y0 = GCD( a, b);
// 此时的 a`就是GCD( a, b)
// 然后根据a * x0 + b * y0 = GCD( a, b) = GCD( b, a % b) = b * x0` + (a % b) * y0` = b * x0` + (a - a / b * b) * y0`
// 整理得出: GCD( a, b) = y0` * a + (x0` - a / b * y0`) * b 化成这种形式后可以看出(看了好长时间...tcl) 
// a * x0 + b * y0 = a * y0` + b * (x0` - a / b * y0`) * b 所以可以根据此方程算出x0和y0 可以由 a与b还有上次的 x0` 与 y0`算出
int k_GCD(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int d = k_GCD(b,a % b,x,y);//在递归后返回的x与y在这还是上次的x与y
    int temp = x;
    x = y;
    y = temp - a / b * y;
    //经过计算 x 与 y已经经过上面写的对应关系转化成了满足当前方程的x 与 y(方程就是a * x + b * y = GCD(a,b))
    return d;
}
 1 // 下面开始理解线性同余方程里最小整数解
 2 // 根据上面知道同余方程可以化简成a * x + b * y = c 的形式
 3 // 观察 a * x + b * y = c 与 a * x0 + b * y0 = GCD( a, b) 的形式,不难看出这两个方程很像
 4 // 所以根据扩展欧几里得算出的两个x0与y0就够用来算出线性同余方程的x与y
 5 // 具体的对应关系是:x = x0 * (c / GCD( a, b)),y = y0 * (c / GCD( a, b))     
 6 // 根据定理二我们知道但GCD( a, b) = 1 时方程的所有解是可以写成 x = x0 + b * t,y = y0 + a * t
 7 // 这是进行一个小变形也就是 (a / GCD( a, b)) * x0 + (b / GCD( a, b)) * y0 = 1
 8 // 然后写出解系 x = x0 + (b / GCD( a, b)) * t, y = y0 + (a / GCD( a, b)) * t
 9 // 令k = b / GCD( a, b)
10 // 从这里能够发现 x 会加上(b / GCD( a, b))的任意整数倍,那么最小的正整数解就是(x0 % k + k) % k 这里加k是为了防止出现负数的请况
11 // 到此证明结束
12 // 开始写程序
13 
14 int k_gcd(int a,int b,int &x,int &y){
15     if(!b){
16         x = 1;
17         y = 0;
18         return a;
19     }
20     int d = k_gcd(b,a % b,x,y);
21     int temp = x;
22     x = y;
23     y = temp - a / b * y;
24     return d;
25 }
26 
27 void test(int b,int d,int x){
28     int k = b / d;
29     return (x % k + k) % k;//返回的就是最小正整数解
30 }

 

posted @ 2019-05-16 16:18  悠久召唤者  阅读(512)  评论(0编辑  收藏  举报