用途
求解裴蜀方程ax+by=(a,b)的一组解,其中a,b∈N+。
基本原理
扩展欧几里得算法基于这样一个原理:若a=bq+r (q∈Z,r∈[0,b)∩Z),且有bx′+ry′=(b,r) (x,y∈Z),则有x=y′,y=x′−qy′满足ax+by=(a,b)。证明如下:
∵bx′+ry′=(b,r) ,(a,b)=(b,r)
∴bx′+ry′=(a,b)
∵a=bq+r ,x=y′,y=x′−qy′
∴ax+by=(bq+r)y′+b(x′−qy′)=bx′+ry′
∴ax+by=(a,b)
计算过程
先执行欧几里得算法的一般过程,得到b=0的一步时有平凡解x=1,y=c(c为任意整数),再依次回代计算x和y即可。值得注意的是,随着c取值的变化,计算出的一组解也会变化。
算法的时间复杂度为O(log2n)。
具体例子
a | b | q | r | x | y | (a,b) | 方程 ax+by=(a,b) |
---|
12345 | 678 | 18 | 141 | 101 | −1839 | 3 | 12345×101+678×(−1839)=3 |
678 | 141 | 4 | 114 | −21 | 101 | 3 | 678×(−21)+141×101=3 |
141 | 114 | 1 | 27 | 17 | −21 | 3 | 141×17+114×(−21)=3 |
114 | 27 | 4 | 6 | −4 | 17 | 3 | 114×(−4)+27×17=3 |
27 | 6 | 4 | 3 | 1 | −4 | 3 | 27×1+6×(−4)=3 |
6 | 3 | 2 | 0 | 0 | 1 | 3 | 6×0+3×1=3 |
3 | 0 | | | 1 | 0 | 3 | 3×1+0×0=3 |
上述表格的前4列a,b,q,r是自上而下计算的,x,y, (a,b)是由下而上递推的。
上述a=12345,b=678的例子中,不断改变c的取值,计算出的x,y的值如下表。
c | x | y |
---|
−3 | 779 | −14184 |
−2 | 553 | −10069 |
−1 | 327 | −5954 |
0 | 101 | −1839 |
1 | −125 | 2276 |
2 | −351 | 6391 |
3 | −577 | 10506 |
上表相邻两行x的差为226,恰为(12345,678)678;y的差为4115,恰为(12345,678)12345。
解的特征
下面分析c的取值对解的影响。可以证明,若令取c=0时计算出的一组解为(x0,y0),且辗转相除过程中进行除法运算的次数为n,则计算出的解为x=(−1)n+1c(a,b)b+x0,y=(−1)nc(a,b)a+y0。
再来看解的符号。x0的符号和(−1)n相同,y0的符号和(−1)n+1相同。当c<0时,x,y的符号分别和x0,y0相同;当c>0时,x,y的符号分别和x0,y0相反。
程序代码
下面程序中取c=0,即上表的情形。实际编写程序时只需使用工具函数exgcd(a,b,x,y)
即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> using namespace std; int exgcd(int a,int b,int &x,int &y); int main(void){ int a,b,d,x,y; cin >> a >> b; d=exgcd(a,b,x,y); cout << "裴蜀方程" << a << "x+" << b << "y=" << d; cout << "的一组解是" << "x=" << x << "y=" << y << endl; return 0; } int exgcd(int a,int b,int &x,int &y){ int xx,yy,d,q,r; if (b==0){ x=1,y=0; return a; } q=a/b,r=a%b; d=exgcd(b,r,xx,yy); x=yy,y=xx-q*yy; return d; }
|