Phương trình Diophantine tuyến tính tự nhiên


13

Một phương trình Diophantine tuyến tính trong hai biến là một phương trình có dạng ax + by = c , trong đó a , bc là các số nguyên không đổi và xy là các biến nguyên.

Đối với nhiều phương trình Diophantine xuất hiện tự nhiên, xy đại diện cho các đại lượng không thể âm.

Bài tập

Viết chương trình hoặc hàm chấp nhận các hệ số a , bc làm đầu vào và trả về một cặp số tự nhiên tùy ý (0, 1, 2, Khắc) xy xác minh phương trình ax + by = c , nếu một cặp như vậy tồn tại

Quy tắc bổ sung

  • Bạn có thể chọn bất kỳ định dạng nào cho đầu vào và đầu ra chỉ liên quan đến các số nguyên mong muốn và, tùy ý, ký hiệu mảng / danh sách / ma trận / tuple / vector của ngôn ngữ của bạn, miễn là bạn không nhúng bất kỳ mã nào vào đầu vào.

  • Bạn có thể giả sử rằng các hệ số ab đều khác không.

  • Mã của bạn phải hoạt động cho bất kỳ bộ ba số nguyên nào trong khoảng từ -2 60 đến 2 60 ; nó phải hoàn thành trong vòng một phút trên máy của tôi (Intel i7-3770, RAM 16 GiB).

  • Bạn không được sử dụng bất kỳ công cụ tích hợp nào giải quyết các phương trình Diophantine và do đó tầm thường hóa nhiệm vụ này, chẳng hạn như Mathicala FindInstancehoặc FrobeniusSolve.

  • Mã của bạn có thể hoạt động theo bất kỳ cách nào bạn muốn nếu không tìm thấy giải pháp nào, miễn là nó tuân thủ giới hạn thời gian và đầu ra của nó không thể bị nhầm lẫn với một giải pháp hợp lệ.

  • Luật tiêu chuẩn được áp dụng.

Ví dụ

  1. Các ví dụ dưới đây minh họa I / O hợp lệ cho phương trình 2x + 3y = 11 , có chính xác hai giải pháp hợp lệ ( (x, y) = (4,1)(x, y) = (1,3) ).

    Input:  2 3 11
    Output: [4 1]
    
    Input:  (11 (2,3))
    Output: [3],(1)
    
  2. Giải pháp hợp lệ duy nhất của 2x + 3y = 2 là cặp (x, y) = (1,0) .

  3. Các ví dụ dưới đây minh họa I / O hợp lệ cho phương trình 2x + 3y = 1 , không có giải pháp hợp lệ .

    Input:  (2 3 1)
    Output: []
    
    Input:  1 2 3
    Output: -1
    
    Input:  [[2], [3], [1]]
    Output: (2, -1)
    
  4. Đối với (a, b, c) = (1152921504606846883, -576460752303423433, 1) , tất cả các giải pháp đúng (x, y) thoả mãn rằng (x, y) = (135637824071393749 - tỷ, 271275648142787502 + an) đối với một số nguyên không âm n .


Tôi nghĩ rằng có thể tốt hơn khi nhấn mạnh hơn một chút vào các số nguyên không âm, và ví dụ thứ hai trong thực tế không có giải pháp.
Sp3000

intput 1 2 3 có đầu ra hợp lệ mặc dù ... [1, 1]
Jack Ammo

@JackAmmo: Tất cả các ví dụ trong khối mã thứ hai tương ứng với 2x + 3y = 1 .
Dennis

Trong ax + bx = k tôi dường như hiểu rằng giải pháp phải là x> = 0 và y> = 0. Vậy ai là những giải pháp x, y> = 0 như 38 * x + 909 * y = 3?
RosLuP

Trong trường hợp như vậy, có lẽ tôi phải trả lại giải pháp không tồn tại đó ...
RosLuP

Câu trả lời:


6

Bình thường, 92 byte

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

Nó khá là quái vật.

Dùng thử trực tuyến: Trình diễn . Định dạng đầu vào là c\n[a,b]và định dạng đầu ra là [x,y].

Trong trường hợp không có giải pháp số nguyên nào tồn tại, tôi sẽ không in gì cả và trong trường hợp không có giải pháp số nguyên tự nhiên nào tồn tại, tôi chỉ cần in một giải pháp số nguyên ngẫu nhiên.

Giải thích (Tổng quan thô)

  1. Đầu tiên tôi sẽ tìm một giải pháp số nguyên cho phương trình ax + by = gcd(a,b)bằng cách sử dụng thuật toán Euclide mở rộng.

  2. Sau đó, tôi sẽ sửa đổi giải pháp (nhân abvới c/gcd(a,b)) để có được một giải pháp số nguyên ax + by = c. Điều này hoạt động, nếu c/gcd(a,b)là một số nguyên. Nếu không thì không tồn tại một giải pháp.

  3. Tất cả các giải pháp số nguyên khác có dạng a(x+n*b/d) + b(y-n*a/d) = c với d = gcd(a,b)số nguyên n. Sử dụng hai bất đẳng thức x+n*b/d >= 0y-n*a/d >= 0tôi có thể xác định 6 giá trị có thể cho n. Tôi sẽ thử tất cả 6 trong số chúng và in giải pháp với hệ số thấp nhất cao nhất.

Giải thích (Chi tiết)

Bước đầu tiên là tìm một giải pháp số nguyên cho phương trình ax' + by' = gcd(a,b). Điều này có thể được thực hiện bằng cách sử dụng thuật toán Euclide mở rộng. Bạn có thể có một ý tưởng về cách nó hoạt động tại Wikipedia . Sự khác biệt duy nhất là, thay vì sử dụng 3 cột ( r_i s_i t_i) tôi sẽ sử dụng 6 cột ( r_i-1 r_i s_i-1 s_i t_i-1 t_i). Bằng cách này, tôi không phải giữ hai hàng cuối cùng trong bộ nhớ, chỉ có hàng cuối cùng.

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. 

Bây giờ tôi muốn tìm một giải pháp để ax + by = c. Điều này chỉ có thể, khi c mod gcd(a,b) == 0. Nếu phương trình này được thỏa mãn, tôi chỉ cần nhân x',y'với 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]

Chúng tôi có một giải pháp số nguyên cho ax + by = c. Lưu ý rằng x, yhoặc cả hai có thể là tiêu cực. Vì vậy, mục tiêu của chúng tôi là biến đổi những thứ này thành không tiêu cực.

Điều hay ho về phương trình Diophantine là, chúng ta có thể mô tả tất cả các giải pháp chỉ bằng một giải pháp ban đầu. Nếu (x,y)là một giải pháp, tất cả các giải pháp khác đều có dạng (x-n*b/gcd(a,b),y+n*a/gcd(a,b))cho nsố nguyên.

Vì vậy, chúng tôi muốn tìm một n, ở đâu x-n*b/gcd(a,b) >= 0y+n*a/gcd(a,b >= 0. Sau một số biến đổi, chúng tôi kết thúc với hai bất đẳng thức n >= -x*gcd(a,b)/bn >= y*gcd(a,b)/a. Lưu ý rằng biểu tượng bất bình đẳng có thể nhìn theo hướng khác do sự phân chia có tiềm năng ahoặc b. Tôi không quan tâm nhiều đến điều đó, tôi chỉ đơn giản nói rằng một số -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1bất đẳng thức thỏa mãn bất đẳng thức 1 và một số y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1bất đẳng thức thỏa mãn 2. Có một n, thỏa mãn cả hai bất đẳng thức, một trong 6 số cũng có.

Sau đó, tôi tính toán các giải pháp mới (x-n*b/gcd(a,b),y+n*a/gcd(a,b))cho tất cả 6 giá trị có thể có n. Và tôi in giải pháp với giá trị thấp nhất cao nhất.

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

Việc sắp xếp theo thứ tự sắp xếp của họ hoạt động theo cách sau. Tôi đang sử dụng ví dụ2x + 3y = 11

Tôi sắp xếp từng trong số 6 giải pháp (đây được gọi là khóa) và sắp xếp các giải pháp ban đầu theo các khóa của chúng:

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]

Điều này sắp xếp một giải pháp hoàn toàn không tiêu cực đến cùng (nếu có).


1
  • sau những nhận xét của Dennis, điều đó làm cho ý tưởng trước đây của tôi bị đảo lộn, tôi đã phải thay đổi mã từ gốc của nó và tôi phải gỡ lỗi lâu dài và khiến tôi phải trả gấp đôi số byte: '(.

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
  • Chà, tôi biết nó không bị đánh gôn, vì loại ngôn ngữ đó không thích nghi với việc giảm độ dài mã, nhưng, tôi có thể đảm bảo rằng độ phức tạp của thời gian là tốt nhất.

Giải trình:

  • mã lấy ba bất biến a, b, c làm đầu vào, những cái cuối cùng này được đặt trong một vài điều kiện trước khi tiến hành tính toán:

    1- nếu (a + b> c) và (a, b, c> 0) không có giải pháp!

    2- nếu (a + b <c), (a, b, c <0) không có giải pháp!

    3- nếu (a, b) có các dấu hiệu trái ngược chung của c: không có giải pháp!

    4 - nếu GCD (a, b) dosnt chia c, thì không có giải pháp nào nữa! , nếu không, chia tất cả các biến thể cho GCD.

  • sau này, chúng ta phải kiểm tra một điều kiện khác, nó sẽ dễ dàng và rút ngắn đường đến giải pháp mong muốn.

    5- nếu c chia a hoặc b, nghiệm s = (x hoặc y) = (c- [ax, yb]) / [b, a] = C / [b, a] + [ax, yb] / [b , a] = S + [ax, yb] / [b, a] trong đó S là tự nhiên nên ax / b hoặc by / a sẽ có các giải pháp trực tiếp không âm tương ứng là x = b hoặc y = a. (lưu ý rằng các giải pháp có thể chỉ là giá trị không trong trường hợp các giải pháp tùy ý trước đó được tiết lộ tiêu cực)

  • thay vào đó, khi chương trình đạt đến giai đoạn này, một phạm vi các giải pháp hẹp hơn cho x = (c-yb) / a được quét thay vào đó, nhờ sự đồng nhất, quét các phạm vi số lớn hơn, được lặp đi lặp lại theo chu kỳ thông thường. trường tìm kiếm lớn nhất là [xa, x + a] trong đó a là ước số.

THỬ NÓ


euuh, vấn đề số lượng lớn, sẽ khắc phục điều đó (tự hỏi khi lol)
Abr001am

Tôi nghĩ rằng vẫn còn một lỗi nhỏ cần khắc phục, về số nguyên lớn, tôi vẫn không hiểu tại sao chia 1152921504606846800.000000 / 576460752303423420.000000 xuất hiện với số 2 tự nhiên, mặc dù kết quả cuối cùng này được làm tròn.
Abr001am

ồ tôi quên sửa lỗi đó: p cảm ơn vì đã chú ý đến nó @Jakube
Abr001am

0

Tiên đề, 460 byte

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))

ungolf và một số bài kiểm tra

-- 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

Trong các 'giải pháp' khác có thể có một lỗi vì nó đã cố lưu các giải pháp vô hạn trong một Danh sách; bây giờ nó được áp đặt giới hạn tối đa 80 giải pháp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.