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]
입니다.
정수 솔루션이 존재하지 않으면 아무것도 인쇄하지 않고 자연 정수 솔루션이 존재하지 않으면 임의의 정수 솔루션을 인쇄합니다.
설명 (거친 개요)
먼저 ax + by = gcd(a,b)
Extended Euclidean 알고리즘을 사용하여 방정식 에 대한 정수 솔루션을 찾습니다 .
그럼 난 솔루션 (내 곱셈 수정할 수 있습니다 a
와 b
함께을 c/gcd(a,b)
의 정수 솔루션을 얻기 위해) ax + by = c
. c/gcd(a,b)
정수 이면 작동 합니다. 그렇지 않으면 해결책이 없습니다.
다른 모든 정수 솔루션 형태로 가지고 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]
이것은 음이 아닌 완전한 솔루션을 끝까지 정렬합니다 (있는 경우).