สมการไดโอแฟนไทน์เชิงเส้นตามธรรมชาติ


13

สมการไดโอแฟนไทน์เชิงเส้นในสองตัวแปรคือสมการของรูปแบบax + โดย = cโดยที่a , bและcเป็นจำนวนเต็มคงที่และxและyเป็นตัวแปรจำนวนเต็ม

สำหรับสมการไดโอแฟนไทน์ที่เกิดขึ้นตามธรรมชาติจำนวนมากxและyแทนปริมาณที่ไม่สามารถลบได้

งาน

เขียนโปรแกรมหรือฟังก์ชั่นที่ยอมรับค่าสัมประสิทธิ์a , bและ cเป็นอินพุตและส่งกลับค่าจำนวนคู่ตามธรรมชาติ (0, 1, 2, …) xและyที่ตรวจสอบสมการขวาน + โดย = cหากคู่ดังกล่าว ที่มีอยู่

กฎเพิ่มเติม

  • คุณสามารถเลือกรูปแบบใดก็ได้สำหรับอินพุตและเอาท์พุตที่เกี่ยวข้องกับจำนวนเต็มเท่านั้นที่ต้องการและตัวเลือกสัญลักษณ์ / array / list / matrix / tuple / vector ของภาษาของคุณตราบใดที่คุณไม่ต้องฝังโค้ดใด ๆ ในอินพุต

  • คุณอาจสมมติว่าค่าสัมประสิทธิ์aและbเป็นทั้งที่ไม่ใช่ศูนย์

  • รหัสของคุณจะต้องทำงานให้แฝดใด ๆ ของจำนวนเต็มระหว่าง-2 60และ2 60 ; จะต้องเสร็จสิ้นภายในไม่กี่นาทีบนเครื่องของฉัน (Intel i7-3770, 16 GiB RAM)

  • คุณไม่สามารถใช้บิวด์อินที่แก้สมการไดโอแฟนไทน์ได้และทำให้งานนี้เป็นเรื่องเล็กน้อยเช่น Mathematica FindInstanceFrobeniusSolveหรือ

  • รหัสของคุณอาจทำงานได้ตามที่คุณต้องการหากไม่พบวิธีแก้ปัญหาตราบใดที่มันเป็นไปตามเวลาที่กำหนดและผลลัพธ์ของมันจะไม่สับสนกับทางออกที่ถูกต้อง

  • มาตรฐาน ใช้กฎ

ตัวอย่าง

  1. ตัวอย่างด้านล่างแสดง I / O ที่ถูกต้องสำหรับสมการ2x + 3y = 11ซึ่งมีโซลูชันที่ใช้ได้สองตัว ( (x, y) = (4,1)และ(x, y) = (1,3 )

    Input:  2 3 11
    Output: [4 1]
    
    Input:  (11 (2,3))
    Output: [3],(1)
    
  2. ทางออกที่ถูกต้องเพียง2x + 3y = 2คือคู่ (x, y) = (1,0)

  3. ตัวอย่างด้านล่างแสดงให้เห็นที่ถูกต้อง I / O สำหรับสมการ2x + 3y = 1ซึ่งมีไม่มีการแก้ปัญหาที่ถูกต้อง

    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)การแก้ปัญหาที่ถูกต้องทั้งหมด(x, y)ตอบสนองความว่า(x, y) = (135637824071393749 - พันล้าน 271275648142787502 +) ที่สำหรับบางคนที่ไม่ใช่เชิงลบจำนวนเต็มn .


ฉันคิดว่ามันอาจเป็นการดีที่จะให้ความสำคัญกับจำนวนเต็มมากกว่าค่าลบและตัวอย่างที่สองที่จริงแล้วไม่มีวิธีแก้ปัญหา
Sp3000

intput 1 2 3 มีเอาต์พุตที่ถูกต้องแม้ว่า ... [1, 1]
Jack Ammo

@JackAmmo: ตัวอย่างทั้งหมดในที่สองตรงรหัสบล็อก2x + 3y = 1
Dennis

ใน ax + bx = k ดูเหมือนว่าฉันจะเข้าใจว่าโซลูชันต้องเป็น x> = 0 และ y> = 0 แล้วใครคือ x, y> = 0 คำตอบของ 38 * x + 909 * y = 3
RosLuP

ในกรณีเช่นนี้อาจจะฉันต้องย้อนกลับไปว่าการแก้ปัญหาไม่ได้อยู่ ...
RosLuP

คำตอบ:


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)โดยใช้อัลกอริทึม Extended Euclidean

  2. แล้วฉันจะปรับเปลี่ยนวิธีการแก้ปัญหา (คูณของฉันaและbมีc/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) nใช้ทั้งสองความไม่เท่าเทียมกันx+n*b/d >= 0และy-n*a/d >= 0ผมสามารถกำหนดค่าที่เป็นไป 6 nสำหรับ ฉันจะลองทั้ง 6 ตัวแล้วพิมพ์คำตอบด้วยค่าสัมประสิทธิ์ต่ำสุดสูงสุด

คำอธิบาย (รายละเอียด)

ax' + by' = gcd(a,b)ขั้นตอนแรกคือการหาวิธีการแก้ปัญหาจำนวนเต็มสมการ สิ่งนี้สามารถทำได้โดยใช้อัลกอริทึมแบบยุคลิดแบบขยาย คุณสามารถได้รับความคิดในการทำงานที่วิกิพีเดีย ข้อแตกต่างคือว่าแทนที่จะใช้ 3 คอลัมน์ ( r_i s_i t_i) ฉันจะใช้ 6 คอลัมน์ ( r_i-1 r_i s_i-1 s_i t_i-1 t_i) วิธีนี้ฉันไม่ต้องเก็บสองแถวสุดท้ายไว้ในหน่วยความจำเพียงแถวสุดท้าย

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เรามีวิธีการแก้ปัญหาสำหรับจำนวนเต็ม แจ้งให้ทราบว่าx, yหรือทั้งสองอาจจะเป็นเชิงลบ ดังนั้นเป้าหมายของเราคือเปลี่ยนสิ่งเหล่านี้ให้ไม่ใช่เชิงลบ

สิ่งที่ดีเกี่ยวกับสมการไดโอแฟนไทน์คือเราสามารถอธิบายการแก้ปัญหาทั้งหมดโดยใช้วิธีแก้ปัญหาเริ่มต้นเพียงหนึ่งเดียว หาก(x,y)เป็นวิธีการแก้ปัญหานั้นโซลูชั่นอื่น ๆ ทั้งหมดอยู่ในรูปแบบ(x-n*b/gcd(a,b),y+n*a/gcd(a,b))ของnจำนวนเต็ม

ดังนั้นเราจึงต้องการที่จะหาnที่และx-n*b/gcd(a,b) >= 0 y+n*a/gcd(a,b >= 0หลังจากการเปลี่ยนแปลงบางอย่างที่เราจบลงด้วยการที่ทั้งสองความไม่เท่าเทียมกันและn >= -x*gcd(a,b)/b n >= 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ที่ตอบสนองความไม่เท่าเทียมกัน

แล้วฉันจะคำนวณโซลูชั่นใหม่(x-n*b/gcd(a,b),y+n*a/gcd(a,b))สำหรับค่าที่เป็นไปได้ทั้งหมด n6 และฉันพิมพ์โซลูชันด้วยค่าต่ำสุดสูงสุด

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
  • หลังจากคำพูดของเดนนิสที่ทำให้ความคิดก่อนหน้าของฉันกลับหัวกลับหางฉันต้องเปลี่ยนรหัสจากรากของมันและใช้เวลาในการดีบั๊กระยะยาวและเสียค่าใช้จ่ายเป็นสองเท่า

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 หรือโดย / a จะมีวิธีแก้ปัญหาโดยตรงต่อไปนี้ไม่ใช่เชิงลบซึ่งตามลำดับ x = b หรือ y = a (แจ้งให้ทราบว่าการแก้ปัญหาสามารถเป็นเพียงค่าศูนย์ในกรณีที่วิธีแก้ไขปัญหาก่อนหน้านี้มีการเปิดเผยเชิงลบ)

  • เมื่อโปรแกรมมาถึงขั้นตอนนี้โซลูชันที่แคบลงสำหรับ x = (c-yb) / a ถูกกวาดแทนเนื่องจากความสอดคล้องกันของการกวาดช่วงของตัวเลขที่กว้างขึ้นซึ่งเกิดขึ้นซ้ำ ๆ ตามรอบปกติ ช่องค้นหาที่ใหญ่ที่สุดคือ [xa, x + a] โดยที่ a คือตัวหาร

ลองมัน


euuh, ปัญหาจำนวนมาก, จะแก้ไขได้ (สงสัยเมื่อ lol)
Abr001am

ฉันคิดว่ามันยังมีข้อผิดพลาดเล็กน้อยในการแก้ไขเกี่ยวกับจำนวนเต็มขนาดใหญ่ฉันยังไม่เข้าใจว่าทำไมการหาร
Abr001am

โอ้ว ฉันลืมที่จะแก้ไขข้อผิดพลาดที่ bugging: p ขอบคุณที่สังเกตมัน @Jakube
Abr001am

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

ungolf และการทดสอบบางอย่าง

-- 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 โซลูชั่นสูงสุด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.