方程“a + bx = c + dy”的积分解

时间:2013-10-12 20:01:12

标签: c++ math equation equation-solving integer-arithmetic

在等式a + bx = c + dy中,所有变量都是整数。 abcd已知。如何找到xy的完整解决方案?如果我正在思考,将会有无数个解决方案,由bd的最低公倍数分隔,但我需要的只是一个解决方案,我可以计算其余的。这是一个例子:

a = 2
b = 3
c = 4
d = 5
a + bx: (2, 5,  8, 11, 14)
c + dy: (4, 9, 14, 19, 24)

a + bx intersects c + dy at 14, so:
x = 4
y = 2

现在,我循环遍历x的整数值,直到找到y(伪代码)的整数值:

function integral_solution(int a, int b, int c, int d) {
    // a + bx == c + dy
    // (a + bx - c) / d == y

    // Some parameters may have no integral solution,
    // for example if b == d and (a - c) % b != 0
    // If we don't have a solution before x == d, there is none.

    int x = 0;
    while (x < d)
    {
        if ((a + bx - c) % d == 0)
        {
            return [x, (a + bx - c) / d];
        }
        x++;
    }
    return false;
}

我觉得有更好的方法来做到这一点。有没有办法找到没有循环的x和y?我正在使用C ++,如果这是重要的。

1 个答案:

答案 0 :(得分:26)

Linear Diophantine等式采用ax + by = c形式。如果cab的最大公约数,则表示a=z'cb=z''c,那么这是<{p}的Bézout's identity >

enter image description here

使用a=z'b=z''并且等式具有无限数量的解。因此,如果cab最大公约数(GCD),则可以检查,而不是试用搜索方法。在您的情况下,这将转换为bx - dy = c - a

如果确实abc的倍数,那么xy可以使用找到整数的extended Euclidean algorithm来计算{{}满足Bézout身份的1}}和x(其中一个通常是负面的)

enter image description here

你的答案是:

ya = k*xb = k*y适用于任何整数 k

(作为旁注:这也适用于任何其他Euclidean domain,即多项式环&amp;每个欧几里德域都是unique factorization domain)。您可以使用迭代方法来查找这些解决方案:


迭代方法

通过扩展和分组类似术语的常规代数(参见前面提到的wikipedia article的最后一节),获得了以下迭代方法算法:

  • 1。应用欧几里德算法,让qn(n从1开始)成为除法中有限的商数列表。
  • 2。将x0,x1初始化为1,0和y0,y1分别为0,1。
    • 2.1然后,只要qi被定义,每个i,
    • 2.2计算xi + 1 = xi-1 - qixi
    • 2.3计算yi + 1 = yi-1 - qiyi
    • 2.4将i递增1后重复上述步骤。
  • 3。答案是xn和yn的倒数第二。

伪代码:

c - a = k * gcd(a,b)

所以我编写了一个示例算法,使用 Euclidean算法迭代方法计算最大公约数非负function extended_gcd(a, b) x := 0 lastx := 1 y := 1 lasty := 0 while b ≠ 0 quotient := a div b (a, b) := (b, a mod b) (x, lastx) := (lastx - quotient*x, x) (y, lasty) := (lasty - quotient*y, y) return (lastx, lasty) a(对于否定 - 需要these额外步骤),它返回GCD并将bx的解决方案存储在通过引用传递给它的变量中:

y

从维基百科传递int gcd_iterative(int a, int b, int& x, int& y) { int c; std::vector<int> r, q, x_coeff, y_coeff; x_coeff.push_back(1); y_coeff.push_back(0); x_coeff.push_back(0); y_coeff.push_back(1); if ( b == 0 ) return a; while ( b != 0 ) { c = b; q.push_back(a/b); r.push_back(b = a % b); a = c; x_coeff.push_back( *(x_coeff.end()-2) -(q.back())*x_coeff.back()); y_coeff.push_back( *(y_coeff.end()-2) -(q.back())*y_coeff.back()); } if(r.size()==1) { x = x_coeff.back(); y = y_coeff.back(); } else { x = *(x_coeff.end()-2); y = *(y_coeff.end()-2); } std::vector<int>::iterator it; std::cout << "r: "; for(it = r.begin(); it != r.end(); it++) { std::cout << *it << "," ; } std::cout << "\nq: "; for(it = q.begin(); it != q.end(); it++) { std::cout << *it << "," ; } std::cout << "\nx: "; for(it = x_coeff.begin(); it != x_coeff.end(); it++){ std::cout << *it<<",";} std::cout << "\ny: "; for(it = y_coeff.begin(); it != y_coeff.end(); it++){ std::cout << *it<<",";} return a; } a = 120b = 23我们获得{/ 1}}:

int main(int argc, char** argv) {   
    // 120x + 23y = gcd(120,23)
    int x_solution, y_solution;
    int greatestCommonDivisor =  gcd_iterative(120, 23, x_solution, y_solution);
    return 0;
}

r:5,3,2,1,0,

q:5,4,1,1,2,

x:1,0,1,-4,5,-9,23,

y:0,1,-5,21,-26,47,-120,

符合此示例的给定表格的内容:

enter image description here