자연적으로 선형 인 디오 판틴 방정식


13

두 변수 의 선형 디오 판틴 방정식 은 ax + by = c 형식의 방정식입니다. 여기서 a , b 및 c 는 상수 정수이고 x 및 y 는 정수 변수입니다.

많은 자연 발생 디오 판틴 방정식에서 x 와 y 는 음수가 될 수없는 양을 나타냅니다.

직무

계수받는 프로그램이나 함수 작성 , B 및 C 를 입력으로하고 임의의 쌍의 리턴 자연수 (0, 1, 2 것은, ...) , X 및 Y 방정식 확인하는 것이 = C로 AX +를 , 예컨대 한 쌍의 경우, 존재합니다.

추가 규칙

  • 입력에 코드를 포함하지 않는 한 원하는 정수만 포함하고 선택적으로 언어의 배열 / 목록 / 매트릭스 / 튜플 / 벡터 표기법과 관련된 입력 및 출력 형식을 선택할 수 있습니다.

  • 계수 a 와 b 가 모두 0이 아닌 것으로 가정 할 수 있습니다 .

  • 코드는 -2 60 과 2 60 사이의 정수의 삼중 항에 대해 작동해야합니다 . 내 컴퓨터에서 1 분 안에 완료해야합니다 (Intel i7-3770, 16 GiB RAM).

  • 당신은 매스 매 티카의 같은 디오판토스 방정식을 해결하고, 따라서이 작업을 하찮게 기본 제공 기능, 사용하지 않을 수 있습니다 FindInstance또는 FrobeniusSolve.

  • 그러나 시간 제한을 준수하고 출력을 유효한 솔루션과 혼동 할 수없는 경우 솔루션을 찾을 수없는 경우 코드가 원하는대로 작동 할 수 있습니다.

  • 표준 규칙이 적용됩니다.

예

  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. 2x + 3y = 2 의 유일한 유효한 솔루션은 (x, y) = (1,0) 쌍 입니다.

  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) 모두 정확한 솔루션 (X는, Y) 이 만족 - (X, Y) = (BN, 271,275,648,142,787,502 + 135,637,824,071,393,749)를 약간 음이 아닌 정수에 대한 N .


음이 아닌 정수를 조금 더 강조하는 것이 좋으며 실제로 두 번째 예에는 해결책이 없다고 생각합니다.
— Sp3000

intput 1 2 3은 유효한 출력을 가지고 있지만 ... [1, 1]
— Jack Ammo

@JackAmmo : 두 번째 코드 블록의 모든 예제는 2x + 3y = 1에 해당합니다 .
— Dennis

ax + bx = k에서 솔루션은 x> = 0이고 y> = 0이어야한다는 것을 이해하는 것 같습니다. 그렇다면 38 * x + 909 * y = 3의 x, y> = 0 해는 누구입니까?
— 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)입니다. 확장 된 유클리드 알고리즘을 사용하여 수행 할 수 있습니다. Wikipedia 에서 작동 방식에 대한 아이디어를 얻을 수 있습니다 . 유일한 차이점은 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또는 둘 모두 음수가 될 수 있습니다. 따라서 우리의 목표는 이것들을 음이 아닌 것으로 바꾸는 것입니다.

Diophantine 방정식의 장점은 하나의 초기 솔루션 만 사용하여 모든 솔루션을 설명 할 수 있다는 것입니다. (x,y)솔루션 인 경우 다른 모든 솔루션은 정수 형식 (x-n*b/gcd(a,b),y+n*a/gcd(a,b))입니다 n.

따라서 우리는 n, where 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))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
  • Dennis의 발언 후, 이전 아이디어를 거꾸로 만들었습니다. 근본에서 코드를 변경해야했고 장기 디버깅이 필요했으며 두 번 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
  • 글쎄, 나는 그 유형의 언어가 코드 길이 단축에 적합하지 않기 때문에 골프를 치지 않는다는 것을 알고 있지만, 시간 복잡성이 최상임을 보장 할 수 있습니다.

설명:

  • 이 코드는 3 개의 불변량 a, b, c를 입력으로 취하고,이 마지막 값은 계산을 진행하기 전에 몇 가지 조건에 종속됩니다.

    1- (a + b> c) 및 (a, b, c> 0) 해결책이없는 경우!

    2- if (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

나는 여전히 큰 정수에 대해 수정하는 사소한 버그를 생각하지만, 왜 1152921504606846800.000000 / 576460752303423420.000000을 나누는 것이 자연수 2로 나오는지 알지 못합니다.이 마지막 결과는 반올림되지만.
— Abr001am 2016 년

아. 나는 도청의 버그를 수정하는 것을 잊었다 : 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.