扩展欧几里得问题

求解证明的方法比较麻烦 为了方便理解我也前后写了不少 今天才完成

关于扩展欧几里德算法主要是证明理解方面要花功夫 下面先给网络上大牛的文章

网上大牛的博文:http://www.cnblogs.com/comeon4mydream/archive/2011/07/18/2109060.html

百度百科:http://baike.baidu.com/view/1478219.htm

 

以下是我自己对整个过程的总结

我们先了解下欧几里德算法:

欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。

gcd(a,b) 表示 a,b的最大公约数,一般程序里也用同名函数来计算最大公约数

计算原理如下:(b不为0时 且a和b不相等的情况下)

我们设gcd(a,b)=d 

再设a除以b的余数为r1 并且必有r1<b

那么必然有非负整数x0使得a=b*x0+r1等式成立 可变为r1=a-b*x0   

那么r1必然也是d的倍数 这样就有a b r1的最大公约数为d

就是说 d=gcd(a,b)=gcd(b,r1)  其中 b>r1

 

如此我们再设b除以r1的余数为r2 并且必有r2<r1

那么必然有非负整数x1使得b=r1*x1+r2等式成立 可变为r2=b-r1*x1   

那么r2必然也是d的倍数 这样就有a b r1 r2的最大公约数为d  

就是说 d=gcd(a,b)=gcd(b,r1)=gcd(r1,r2) 其中 b>r1>r2

 

这样反复我们就会得出 d=gcd(a,b)=gcd(b,r1)=gcd(r1,r2)=……=gcd(rn-1,rn) 其中 b>r1>r2>……>rn-1>rn=d

那么必然有非负整数xn-1使得rn-2=(rn-1*xn-1) +rn等式成立 可变为rn=rn-2 -(rn-1*xn-1)

然后我们发现rn-1除以rn其余数就为0 这就可以判断rn为最大公约数d

 

这就是欧几里德算法求最大公约数的算法了(上述算法当a=b的时候我们可知最大公约数就为其本身同样适用 同时我们规定当b=0的时候gcd(a,b)=a)

我们通过程序来求解就有:

int Gcd(int a, int b)

{

if(b == 0) return a;

return Gcd(b, a % b);

} // 递归形式

以上就是欧几里德算法程序实现方法 

 

 

 

 

然后我们就可以开始了解扩展欧几里德算法了

此算法常用来求解二元一次不定方程 a*x+b*y=c 的整数解

(其中a b c均为整数,不为整数的话我们也可以同乘一个系数来使其都变为整数)

 

我们先从特殊入手 假设c=d=gcd(a,b)这样方程可以写成 a*x+b*y=d

上面解说的时候我们知道求解d的过程 其中间量rn=rn-2 -(rn-1 * xn-1) 

其中xn-1=(rn-2)/(rn-1)( 注意这里是计算机的的除法就是结果向下取整)于是有下面一组式子

rn=rn-2 -(rn-1 * xn-1) 、rn-1=rn-3 -(rn-2*xn-2)  、 rn-2=rn-4 –(rn-3*xn-3)  、……  、r1=a-b*x0

我们把第一个式子d= rn= rn-2 –(rn-1 * xn-1)改写为d=rn=ln*rn-1 +kn*rn-2   其中 ln= -xn-1 、kn=1

我们代入rn-1=rn-3 –(rn-2*xn-2)有d=rn= (kn– ln*xn-2)*rn-2 +ln*rn-3   

我们再次改写为d=rn=ln-1*rn-2 + kn-1*rn-3  于是我们就得出  ln-1=kn - ln*xn-2 、kn-1=ln

有了这个递推公式我们就不断推导求出这个式子d=rn=l1*b+k1*a 而且递推公式里面l与k均为整数

那么我们可以说a*x+b*y=gcd(a,b)=d 必有整数解   x=k1 、y=l1为其中一组解

而且x=k1+t*b/gcd(a,b) 、y=l1-t*a/gcd(a,b) (t为任意整数)表示所有整数解

(对于这个解通式 这里只提一次 b/gcd(a,b)与a/gcd(a,b)为整数而且互质 为两组整数解最小的变化间距)

 

我们扩大c的范围为gcd(a,b)*c0 即c=gcd(a,b)*c0=d*c0

方程改写为为a*x+b*y=d*c0 (c0为整数)  我们用x0*c0=x 、y0*c0=y替换 然后两边都除以c0 

有a*x0+b*y0=d 转化为求x0和y0  根据上一个情况可知其必有整数解

并且x=x0*c0 + t*b/gcd(a,b) 、y=y0*c0 - t*a/gcd(a,b) (t为任意整数)表示所有整数解

    

我们再次扩大c的范围对于任意的a*x+b*y=c我们可以求得d=gcd(a,b) 

并且设a/d=a0  b/d=b0   可知a0 b0均为整数 方程可以改写为a0*x+b0*y=c/d

等式右边只有当c%d==0的时候才可为整数 根据上面的情况可知此时一定有整数解

如果c%d!=0 即c/d为小数 那么没有整数对x y可以让等式左边成为小数 自然不可能有整数解

 

于是 c%gcd(a,b)==0 是方程a*x+b*y=c有整数解的充分必要条件

 

 

 

有了上面的证明 我们就可以来解二元一次不定方程的整数解了

方程a*x+b*y=c   我们先求d=gcd(a,b)

如果c%d!=0 那么肯定无整数解    如果c%d==0 必有整数解

计算整数c0=c/d  用c=c0*d替换 方程可以转化为 a*x+b*y=c0*d 

再用x=x0*c0  y=y0*c0 替换 可以得到方程a*x0+b*y0=d  

如此我们就可以计算整数解x0和y0最后乘以c0 

为了方便计算我们用a0=a/d  b0=b/d替换 方程可以转化为a0*x0+b0*y0=gcd(a0,b0)=1

然后通过欧几里得算法求gcd(a0,b0)(也可以求gcd(a,b) 不会影响结果)的过程

求出中间变量ln=-xn-1  和kn=1  利用递推公式ln-1=kn– ln*xn-2     kn-1 = ln

最后求得x0=k1 y0=l1 最后所有整数解为x=k1*c0 +t*b/gcd(a,b)  y=l1*c0 -t*a/gcd(a,b)  (t为任意整数)

 

 

 

接下来通过程序来实现这个过程

已知a  b  c  

求d=gcd(a,b)  计算过程中用数组x 记录每一次计算的中间值  x[n]= r[n-1] / r[n]

然后判定c%d是否为0  若不为0  方程无整数解 

若为0    利用数组x  计算x0 和 y0    再求出最后的结果x ,y

 

当然我们在递归求d的时候  可以顺带先求出x0 和y0  然后再判断是否可以求解

程序如下

int  k , l                      //全局变量k l 用来计算结果

int gcd(int a, int b)             //创建一个同名函数计算gcd(a,b)   a,b可接受0和负整数

                                             

    int d, t;                     //创建辅助变量

    if (b==0)                     //当b为0的 时候返回结果  这时候a为最后结果  初始化k和l

    { k = 1; l = 0; return a; }

    d = gcd(b, a % b);            //当b不为0的时候向下一层递归  用辅助变量d接受函数结果

    t = k - a/b*l;                //当接受返回值后 就可以计算k和l的在本层的值 t为中间辅助变量

    k = l;

    l = t;

    return d;                     //计算完本层k和l的值后  返回d

                             

递归结束后我们就得到了最后的k和l 此为方程a*x+b*y=gcd(a,b)的一组整数解 

最后的结果(y解同样 我就懒得写了)为  x=k* c/gcd(a,b)+t* b/gcd(a,b)   (t为任意整数)  

 

 

如果求最小正整数解 还要加上下面的方法

对于x 在区间范围 [0,b/gcd(a,b)-1] 有且仅有一解

证明如下: 在区间范围[0,b/gcd(a,b)-1]内    (注意稍微调整下符号 同样在这个区间内)

我们可以带入解的通式 0<= k* c/gcd(a,b)+t* b/gcd(a,b) < b/gcd(a,b)  解得 –k*c/b <= t <1 -k*c/b

t在一个区间宽度只有1的范围内取值 有且仅有一个整数值 使其在区间范围[0,b/gcd(a,b)-1]有整数解

自然求解的方法也出来了:计算-k*c/b 向上取整求得t  把t带入计算最小整数解(y解的情况同上)

关于此类问题 还有一些变形和特殊条件 但是方法类似

 

下面附上专题训练

http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=5378     密码:hbut

要求:都要完成 并且完成一题从头写另一题 不要改改原代码就提交另一题 一定要练习到完全掌握核心思想

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值