Pyth, 92 octets
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'est tout à fait un monstre.
Essayez-le en ligne: démonstration . Le format d'entrée est c\n[a,b]
et le format de sortie est [x,y]
.
Dans le cas où aucune solution entière n'existe, je n'imprimerai rien, et dans le cas où aucune solution entière naturelle n'existe, j'imprimerai simplement une solution entière aléatoire.
Explication (aperçu approximatif)
Dans un premier temps, je vais trouver une solution entière à l'équation ax + by = gcd(a,b)
en utilisant l'algorithme euclidien étendu.
Ensuite, je vais modifier la solution (ma multiplication a
et b
avec c/gcd(a,b)
) pour obtenir une solution entière de ax + by = c
. Cela fonctionne, si c/gcd(a,b)
est un entier. Sinon, il n'existe pas de solution.
Toutes les autres solutions entières ont la forme a(x+n*b/d) + b(y-n*a/d) = c
avec d = gcd(a,b)
for integer n
. En utilisant les deux inégalités x+n*b/d >= 0
et y-n*a/d >= 0
je peux déterminer 6 valeurs possibles pour n
. Je vais essayer les 6 et imprimer la solution avec le coefficient le plus bas le plus élevé.
Explication (détaillée)
La première étape consiste à trouver une solution entière à l'équation ax' + by' = gcd(a,b)
. Cela peut être fait en utilisant l'algorithme euclidien étendu. Vous pouvez vous faire une idée de son fonctionnement sur Wikipedia . La seule différence est qu'au lieu d'utiliser 3 colonnes ( r_i s_i t_i
), j'utiliserai 6 colonnes ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
). De cette façon, je n'ai pas à garder les deux dernières lignes en mémoire, seulement la dernière.
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.
Maintenant, je veux trouver une solution ax + by = c
. Cela n'est possible que lorsque c mod gcd(a,b) == 0
. Si cette équation est satisfaite, je multiplie simplement x',y'
avec 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]
Nous avons une solution entière pour ax + by = c
. Notez que x
, y
ou les deux peuvent être négatifs. Notre objectif est donc de les transformer en non-négatifs.
La bonne chose à propos des équations diophantiennes est que nous pouvons décrire toutes les solutions en utilisant une seule solution initiale. Si (x,y)
est une solution, que toutes les autres solutions sont de la forme (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
pour n
entier.
Par conséquent, nous voulons trouver un n
, où x-n*b/gcd(a,b) >= 0
et y+n*a/gcd(a,b >= 0
. Après une certaine transformation, nous nous retrouvons avec les deux inégalités n >= -x*gcd(a,b)/b
et n >= y*gcd(a,b)/a
. Notez que le symbole d'inégalité peut regarder dans l'autre sens en raison de la division avec un potentiel négatif a
ou b
. Je m'en fiche pas mal, je dis simplement qu'un nombre de -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
satisfait définitivement l'inégalité 1, et un nombre de y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
satisfait l'inégalité 2. Il y a unn
, qui satisfait les deux inégalités, l'un des 6 chiffres aussi.
Ensuite, je calcule les nouvelles solutions (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
pour les 6 valeurs possibles de n
. Et j'imprime la solution avec la valeur la plus basse la plus élevée.
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
Le tri par leur ordre de tri fonctionne de la manière suivante. J'utilise l'exemple2x + 3y = 11
Je trie chacune des 6 solutions (ce sont les clés) et trie les solutions originales par leurs clés:
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]
Cela trie une solution non négative complète à la fin (le cas échéant).