Pyth, 92 bytes
I!%vzhK%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2)J*L/vzhKtKeoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ
Es todo un monstruo.
Pruébelo en línea: demostración . El formato de entrada es c\n[a,b]
y el formato de salida es [x,y]
.
En el caso de que no exista una solución entera, no imprimiré nada, y en el caso de que no exista una solución entera natural, simplemente imprimiré una solución entera aleatoria.
Explicación (descripción general)
Al principio, encontraré una solución entera para la ecuación ax + by = gcd(a,b)
usando el algoritmo Euclidiano Extendido.
Luego modificaré la solución (mi multiplicación a
y b
con c/gcd(a,b)
) para obtener una solución entera de ax + by = c
. Esto funciona, si c/gcd(a,b)
es un número entero. De lo contrario, no existe una solución.
Todas las otras soluciones de enteros tienen la forma a(x+n*b/d) + b(y-n*a/d) = c
con d = gcd(a,b)
for integer n
. Usando las dos desigualdades x+n*b/d >= 0
y y-n*a/d >= 0
puedo determinar 6 valores posibles para n
. Probaré los 6 e imprimiré la solución con el coeficiente más bajo más alto.
Explicación (detallada)
El primer paso es encontrar una solución entera a la ecuación ax' + by' = gcd(a,b)
. Esto se puede hacer usando el algoritmo euclidiano extendido. Puede hacerse una idea de cómo funciona en Wikipedia . La única diferencia es que, en lugar de usar 3 columnas ( r_i s_i t_i
), usaré 6 columnas ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
). De esta manera no tengo que mantener las dos últimas filas en la memoria, solo la última.
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.
Ahora quiero encontrar una solución para ax + by = c
. Esto solo es posible cuando c mod gcd(a,b) == 0
. Si se satisface esta ecuación, simplemente multiplico x',y'
con 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]
Tenemos una solución entera para ax + by = c
. Aviso, que x
, y
o ambos puede ser negativo. Por lo tanto, nuestro objetivo es transformarlos en no negativos.
Lo bueno de las ecuaciones de diofantina es que podemos describir todas las soluciones usando solo una solución inicial. Si (x,y)
es una solución, todas las demás soluciones tienen la forma (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
de n
entero.
Por lo tanto, queremos encontrar un n
, donde x-n*b/gcd(a,b) >= 0
y y+n*a/gcd(a,b >= 0
. Después de alguna transformación, terminamos con las dos desigualdades n >= -x*gcd(a,b)/b
y n >= y*gcd(a,b)/a
. Observe que el símbolo de desigualdad podría mirar en la otra dirección debido a la división con un potencial negativo a
o b
. No me importa mucho, simplemente digo que un número de -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
satisface definitivamente la desigualdad 1, y un número de y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
satisface la desigualdad 2. Si hay un n
, que satisface ambas desigualdades, uno de los 6 números también lo hace.
Luego calculo las nuevas soluciones (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
para los 6 valores posibles de n
. E imprimo la solución con el valor más bajo más alto.
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
La ordenación por su orden ordenado funciona de la siguiente manera. Estoy usando el ejemplo2x + 3y = 11
Ordeno cada una de las 6 soluciones (esto se llama claves), y clasifico las soluciones originales por sus claves:
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]
Esto ordena una solución no negativa completa hasta el final (si hay alguna).