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 ist ein ziemliches Monster.
Probieren Sie es online aus: Demonstration . Das Eingabeformat ist c\n[a,b]
und das Ausgabeformat ist [x,y]
.
Für den Fall, dass keine ganzzahlige Lösung existiert, gebe ich nichts aus und für den Fall, dass keine natürliche ganzzahlige Lösung existiert, gebe ich einfach eine zufällige ganzzahlige Lösung aus.
Erklärung (grobe Übersicht)
Zuerst werde ich eine ganzzahlige Lösung für die Gleichung finden, ax + by = gcd(a,b)
indem ich den erweiterten euklidischen Algorithmus verwende.
Dann ändere ich die Lösung (mein Multiplizieren a
und b
mit c/gcd(a,b)
), um eine ganzzahlige Lösung von zu erhalten ax + by = c
. Dies funktioniert, wenn c/gcd(a,b)
es sich um eine Ganzzahl handelt. Sonst gibt es keine Lösung.
Alle anderen Ganzzahllösungen haben die Form a(x+n*b/d) + b(y-n*a/d) = c
mit d = gcd(a,b)
für Ganzzahl n
. Mit den beiden Ungleichungen x+n*b/d >= 0
und y-n*a/d >= 0
kann ich 6 mögliche Werte für bestimmen n
. Ich probiere alle 6 aus und drucke die Lösung mit dem höchsten und niedrigsten Koeffizienten.
Erklärung (detailliert)
Der erste Schritt besteht darin, eine ganzzahlige Lösung für die Gleichung zu finden ax' + by' = gcd(a,b)
. Dies kann mithilfe des erweiterten euklidischen Algorithmus erfolgen. Bei Wikipedia können Sie sich ein Bild davon machen, wie es funktioniert . Der einzige Unterschied ist, dass r_i s_i t_i
ich anstelle von 3 Spalten ( ) 6 Spalten ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
) verwende. Auf diese Weise muss ich nicht die letzten beiden Zeilen im Speicher behalten, sondern nur die letzte.
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.
Jetzt möchte ich eine Lösung finden ax + by = c
. Dies ist nur möglich, wenn c mod gcd(a,b) == 0
. Wenn diese Gleichung erfüllt ist, multipliziere ich einfach x',y'
mit 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]
Wir haben eine ganzzahlige Lösung für ax + by = c
. Beachten Sie , dass x
, y
oder beide negativ sein kann. Unser Ziel ist es daher, diese in nicht negative umzuwandeln.
Das Schöne an Diophantine-Gleichungen ist, dass wir alle Lösungen mit nur einer Anfangslösung beschreiben können. Wenn (x,y)
es sich um eine Lösung handelt, haben alle anderen Lösungen die Form (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
einer n
Ganzzahl.
Deshalb wollen wir ein n
, wo x-n*b/gcd(a,b) >= 0
und y+n*a/gcd(a,b >= 0
. Nach einer gewissen Transformation kommen wir zu den beiden Ungleichungen n >= -x*gcd(a,b)/b
und n >= y*gcd(a,b)/a
. Beachten Sie, dass das Ungleichungssymbol aufgrund der Division mit einem potenziellen negativen a
oder in die andere Richtung zeigen kann b
. Es ist mir egal, ich sage einfach, dass eine Zahl -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
definitiv die Ungleichung 1 und eine Zahl y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
die Ungleichung 2 erfüllt. Es gibt eine n
, die beide Ungleichungen erfüllt, und eine der 6 Zahlen tut dies auch.
Dann berechne ich die neuen Lösungen (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
für alle 6 möglichen Werte von n
. Und ich drucke die Lösung mit dem höchsten niedrigsten Wert.
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
Das Sortieren nach ihrer sortierten Reihenfolge funktioniert folgendermaßen. Ich benutze das Beispiel2x + 3y = 11
Ich sortiere jede der 6 Lösungen (diese werden als Schlüssel bezeichnet) und sortiere die ursprünglichen Lösungen nach ihren Schlüsseln:
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]
Dies sortiert eine vollständige nicht negative Lösung bis zum Ende (falls vorhanden).