自然线性Diophantine方程


13

两个变量中的线性Diophantine方程ax + by = c形式的方程,其中abc是常数,xy是整数。

对于许多自然发生的丢番图方程,xy表示不能为负的数量。

任务

编写一个接受系数abc作为输入并返回任意对自然数(0、1、2,...)xy的程序或函数,以验证方程ax + by = c(如果有)存在。

附加规则

  • 您可以选择任何只涉及所需整数的语言,只要您不在输入中嵌入任何代码,就可以选择仅涉及所需整数的任何格式,以及(可选)语言的数组/列表/矩阵/元组/矢量表示法。

  • 您可以假设系数ab都非零。

  • 您的代码必须适用于-2 602 60之间的任何三元整数;它必须在一分钟内在我的计算机(Intel i7-3770,16 GiB RAM)上完成。

  • 您可能不使用任何可解决Diophantine方程从而使这项任务变得微不足道的内置函数,例如Mathematica FindInstanceFrobeniusSolve

  • 如果找不到解决方案,只要符合时间限制并且其输出不能与有效解决方案混淆,您的代码可能会按照您希望的方式运行。

  • 适用标准规则。

例子

  1. 下面的示例说明方程2x + 3y = 11的有效I / O,正好具有两个有效解((x,y)=(4,1)(x,y)=(1,3))。

    Input:  2 3 11
    Output: [4 1]
    
    Input:  (11 (2,3))
    Output: [3],(1)
    
  2. (x,y)=(1,0)对是2x + 3y = 2的唯一有效解决方案。

  3. 下面的示例说明方程2x + 3y = 1的有效I / O ,但没有有效解

    Input:  (2 3 1)
    Output: []
    
    Input:  1 2 3
    Output: -1
    
    Input:  [[2], [3], [1]]
    Output: (2, -1)
    
  4. 对于(a,b,c)=(1152921504606846883,-576460752303423433,1),对于某些非负整数n,所有正确的解(x,y)都满足(x,y)=(135637824071393749-bn,271275648142787502 + an)


我认为最好将重点放在非负整数上,并且第二个示例实际上没有解决方案。
Sp3000

intput 1 2 3尽管有一个有效的输出... [1,1]
Jack Ammo 2015年

@JackAmmo:第二个代码块中的所有示例都对应于2x + 3y = 1
丹尼斯

在ax + bx = k的情况下,我似乎理解解决方案必须为x> = 0和y> = 0。那么谁是38 * x + 909 * y = 3的x,y> = 0解?
RosLuP

在这种情况下,我可能必须返回不存在的解决方案...
RosLuP

Answers:


6

Pyth,92个字节

I!%vzhK%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2)J*L/vzhKtKeoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ

这真是一个怪物。

在线尝试:演示。输入格式为c\n[a,b],输出格式为[x,y]

在不存在整数解的情况下,我将不打印任何内容;在不存在自然整数解的情况下,我将仅打印随机整数解决方案。

说明(概述)

  1. 首先,我将ax + by = gcd(a,b)使用扩展欧几里得算法找到方程的整数解。

  2. 然后,我将修改解决方案(我的乘法abc/gcd(a,b)),以获得的整数解ax + by = c。如果c/gcd(a,b)为整数,则此方法有效。否则,不存在解决方案。

  3. 所有其他整数解决方案均a(x+n*b/d) + b(y-n*a/d) = c 具有d = gcd(a,b)for integer 的形式n。使用这两个不等式x+n*b/d >= 0y-n*a/d >= 0我可以确定的6个可能值n。我将尝试所有6种方法,并以最高的最低系数打印解决方案。

说明(详细)

第一步是找到方程的整数解ax' + by' = gcd(a,b)。这可以通过使用扩展的欧几里得算法来完成。您可以在Wikipedia上了解其工作原理。唯一的区别是,r_i s_i t_i我将使用6列(r_i-1 r_i s_i-1 s_i t_i-1 t_i)而不是3 列()。这样,我不必将最后两行保留在内存中,只需保留最后一行。

K%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2)   implicit: Q = [a,b] (from input)
                                     j9 2    convert 9 to base 2: [1,0,0,1]
                            + Q              add to Q => [a,b,1,0,0,1]
                                             this is the initial row
   u                                     )   start with G = ^ and update G repeatedly
                                             by the following expression, until
                                             the value of G doesn't change anymore
    ?                   @G1                    if G[1] != 0:
                     cG2                         split G into parts of 2
      m                                          map the parts d to:
       ,                                           the pair 
        ed                                           d[1]
          -hd*ed/F<G2                                d[0]-d[1]*G[0]/G[1]
     s                                           unfold
                                               else:
                           G                     G (don't change it, stop criterion for u)
 %2                                          take every second element
                                             we get the list [gcd(a,b),x',y']
K                                            store this list in K
                             ~Q,hQ_eQ        afterwards change Q to [Q[0],-Q[1]] = [a,-b]
                                             This will be important for the other parts. 

现在我想找到解决方案ax + by = c。仅当时才有可能c mod gcd(a,b) == 0。如果这个等式被满足,我只是乘x',y'c/gcd(a,b)

I!%vzhK...J*L/vzhKtK   implicit: z = c in string format (from input)
  %vzhK                evaluated(z) mod K[0] (=gcd(a,b))
I!                     if not ^ than: 
             /vzhK        c/K[0]
           *L     tK      multipy ^ to each element in K[1:] (=[x',y'])
          J               and store the result in J, this is now [x,y]

我们有一个整数解决方案ax + by = c。请注意,这xy或两者可能为负。因此,我们的目标是将这些转换为非负数。

关于Diophantine方程的好处是,我们可以仅使用一个初始解来描述所有解。如果(x,y)是一个解决方案,所有其他解决方案的形式是(x-n*b/gcd(a,b),y+n*a/gcd(a,b))n整数。

因此,我们要查找a n,where x-n*b/gcd(a,b) >= 0y+n*a/gcd(a,b >= 0。经过一些转换,我们最终得到两个不等式n >= -x*gcd(a,b)/bn >= y*gcd(a,b)/a。请注意,不等式符号可能会朝另一个方向看,这是因为被潜在的负数a或所除b。我对此并不在乎,我只是简单地说一个数字确实-x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1满足不等式1,而一个数字y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1满足不等式2。有一个n满足两个不等式,6个数字之一也满足。

然后,我(x-n*b/gcd(a,b),y+n*a/gcd(a,b))为的所有6个可能值计算新解n。然后以最高的最低值打印解决方案。

eoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ
                               _J    reverse J => [y,x]
                           *LhK      multiply each value with K[0] => [y*gcd,x*gcd]
                         /V      Q   vectorized division => [y*gcd/a,-x*gcd/b]
                  m                  map each d of ^ to:
                      tM3              [-1,0,1]
                   +Ld                 add d to each ^
                 s                   unfold
                                     these are the possible values for n
    m                                map each d (actually n) of ^ to:
             *LdQ                      multiply d to Q => [a*n,-b*n]
            _                          reverse => [-b*n,a*n]
        /RhK                           divide by K[0] => [-b*n/gcd,a*n/gcd]
     -VJ                               vectorized subtraction with J
                                       => [x+b*n/gcd,y-a*n/gcd]
 oSN                                 order the solutions by their sorted order
e                                    print the last one

按其排序顺序进行排序的工作方式如下。我正在使用示例2x + 3y = 11

我对6个解决方案(称为键)中的每个进行排序,并按其键对原始解决方案进行排序:

solutions: [1, 3], [4, 1], [7, -1], [-5, 7], [-2, 5], [1, 3]
keys:      [1, 3], [1, 4], [-1, 7], [-5, 7], [-2, 5], [1, 3]
sort by key:
solutions: [-5, 7], [-2, 5], [7, -1], [1, 3], [1, 3], [4, 1]
keys:      [-5, 7], [-2, 5], [-1, 7], [1, 3], [1, 3], [1, 4]

这样可以将一个完整的非负解决方案排序到最后(如果有)。


1
  • 在丹尼斯发表讲话后,这使我以前的想法完全颠覆了,我不得不从根本上更改代码,这花费了我长期的调试时间,并且使我浪费了两次n°字节:'(。

Matlab(660)

a=input('');b=input('');c=input('');if((min(a*c,b*c)>c*c)&&a*c>0&&b*c>0)||(a*c<0&&b*c<0),-1,return,end,g=abs(gcd(a,b));c=c/g;a=a/g;b=b/g;if(c~=floor(c)),-1,return,end,if(c/a==floor(c/a)&&c/a>0),e=c/a-b;if(e>0),e,a,return,else,c/a,0,return,end,end,if(c/b==floor(c/b)&&c/b>0),e=c/b-a;if(e>0),b,e,return,else,0,c/b,return,end,end,f=max(abs(a),abs(b));if f==abs(a),f=b;b=a;a=f;g=0.5;end,e=(c-b)/a;f=(c-2*b)/a;if(e<0&&f<e),-1,elseif(e<0&&f>e),for(i=abs(c*a):abs((c+1)*a)),e=(c-i*b);if(mod(e,a)==0)if(g==0.5),i,e/a;else,e/a,i,end,return,end,end,else for(i=1:abs(a)),e=(c-i*b);if(e/a<0),-1,elseif(mod(e,a)==0),if(g==0.5),i,e/a,else,e/a,i,end,return,end,end,end,-1
  • 好吧,我知道它不适合使用,因为这种类型的语言不适合减少代码长度,但是,我可以确保时间复杂度处于最佳状态。

说明:

  • 该代码将三个不变量a,b,c作为输入,在进行计算之前,将这最后两个变量服从几个条件:

    1-如果(a + b> c)和(a,b,c> 0)无解!

    2-如果(a + b <c),(a,b,c <0)无解!

    3-如果(a,b)具有c的相反符号:无解!

    4-如果GCD(a,b)不除以c,则无解!,否则,将所有变体除以GCD。

  • 此后,我们必须检查另一种情况,它应该简化并缩短获得所需解决方案的途径。

    5-如果c除以a或b,则解s =(x或y)=(c- [ax,yb])/ [b,a] = C / [b,a] + [ax,yb] / [b ,a] = S + [ax,yb] / [b,a]其中S是自然的,因此ax / b或by / a今后将具有分别为x = b或y = a的非负直接解。(请注意,如果先前的任意解显示为负数,则解只能是nil值)

  • 当程序到达此阶段时,由于一致性,扫掠了范围更窄的x =(c-yb)/ a的解决方案,它扫荡了较大范围的数字,这是有规律的循环重复出现的。最大的搜索字段是[xa,x + a],其中a是除数。

尝试一下


euuh,大量问题,将解决此问题(大声笑)
Abr001am 2015年

我认为它仍然是较小的错误,有关大整数,我仍然不明白为什么将1152921504606846800.000.00 / 576460752303423420420.000000除以自然数2,尽管最后的结果是四舍五入的。
Abr001am 2015年

哦。我忘了修复该bug:p感谢您注意到@Jakube
Abr001am 2015年

0

公理,460字节

w(a,b,x,u)==(a=0=>[b,x];w(b rem a,a,u,x-u*(b quo a)))
d(a,b,k)==(o:List List INT:=[];a=0 and b=0=>(k=0=>[1,1];[]);a=0=>(k=0=>[[1,0]];k rem b=0=>[1,k quo b];[]);b=0=>(k=0=>[[0,1]];k rem a=0=>[k quo a,1];[]);r:=w(a,b,0,1);q:=k quo r.1;(y,x,u,v):=(q*(r.1-r.2*a)quo b,q*r.2,b quo r.1,a quo r.1);m:=min(80,4+abs(k)quo min(abs(a),abs(b)));l:=y quo v;x:=x+l*u;y:=y-l*v;for n in -m..m repeat(t:=x+n*u;z:=y-n*v;t>=0 and z>=0 and t*a+z*b=k=>(o:=cons([t,z],o)));sort(o))

高尔夫和一些测试

-- input a b and k for equation a*x+b*y=k
-- result one List of List of elments [x,y] of solution of  
-- that equation with x and y NNI (not negative integers) 
-- or Void list [] for no solution
diopanto(a,b,k)==
  o:List List INT:=[]
  a=0 and b=0=>(k=0=>[1,1];[])
  a=0=>(k=0=>[[1,0]];k rem b=0=>[1,k quo b];[])
  b=0=>(k=0=>[[0,1]];k rem a=0=>[k quo a,1];[])
  r:=w(a,b,0,1)
  q:=k quo r.1
  (y,x,u,v):=(q*(r.1-r.2*a)quo b,q*r.2,b quo r.1,a quo r.1)
  m:=min(80,4+abs(k)quo min(abs(a),abs(b)))
  l:=y quo v           -- center the interval
  x:=x+l*u; y:=y-l*v
  for n in -m..m repeat
     t:=x+n*u;z:=y-n*v
     t>=0 and z>=0 and t*a+z*b=k=>(o:=cons([t,z],o))
  sort(o)

 ------------------------------------------------------
(4) -> d(0,-9,0)
   (4)  [[1,0]]
                                                  Type: List List Integer
(5) -> d(2,3,11)
   (5)  [[4,1],[1,3]]
                                                  Type: List List Integer
(6) -> d(2,3,2)
   (6)  [[1,0]]
                                                  Type: List List Integer
(7) -> d(2,3,1)
   (7)  []
                                                  Type: List List Integer
(8) -> d(1152921504606846883,-576460752303423433,1)
   (8)
   [[135637824071393749,271275648142787502],
    [712098576374817182,1424197152749634385],
    [1288559328678240615,2577118657356481268],
    [1865020080981664048,3730040161963328151],
    [2441480833285087481,4882961666570175034]]
                                                  Type: List List Integer

在其他“解决方案”中可能存在一个错误,因为它试图将无限解决方案保存在一个列表中。现在施加了最多80个解决方案的限制

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.