Pyth, 92 byte
I!%vzhK%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2)J*L/vzhKtKeoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ
È piuttosto un mostro.
Provalo online: dimostrazione . Il formato di input è c\n[a,b]
e il formato di output è [x,y]
.
Nel caso in cui non esista una soluzione intera, non stamperò nulla e nel caso in cui non esista una soluzione intera naturale, stamperò semplicemente una soluzione intera casuale.
Spiegazione (Panoramica approssimativa)
All'inizio troverò una soluzione intera all'equazione ax + by = gcd(a,b)
usando l'algoritmo Euclidean esteso.
Quindi modificherò la soluzione (il mio moltiplicando a
e b
con c/gcd(a,b)
) per ottenere una soluzione intera di ax + by = c
. Funziona, se c/gcd(a,b)
è un numero intero. Altrimenti non esiste una soluzione.
Tutte le altre soluzioni intere hanno il modulo a(x+n*b/d) + b(y-n*a/d) = c
con d = gcd(a,b)
for integer n
. Utilizzando le due disuguaglianze x+n*b/d >= 0
e y-n*a/d >= 0
posso determinare 6 possibili valori per n
. Proverò tutti e 6 e stampa la soluzione con il coefficiente più basso più alto.
Spiegazione (dettagliata)
Il primo passo è trovare una soluzione intera all'equazione ax' + by' = gcd(a,b)
. Questo può essere fatto usando l'algoritmo euclideo esteso. Puoi avere un'idea su come funziona su Wikipedia . L'unica differenza è che invece di usare 3 colonne ( r_i s_i t_i
) userò 6 colonne ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
). In questo modo non devo tenere in memoria le ultime due righe, solo l'ultima.
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.
Ora voglio trovare una soluzione per ax + by = c
. Questo è possibile solo quando c mod gcd(a,b) == 0
. Se questa equazione è soddisfatta, sto semplicemente moltiplicando 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]
Abbiamo una soluzione intera per ax + by = c
. Si noti che x
, y
o entrambi possono essere negativi. Quindi il nostro obiettivo è di trasformarli in non negativi.
La cosa bella delle equazioni di Dihanthant è che possiamo descrivere tutte le soluzioni usando solo una soluzione iniziale. Se (x,y)
è una soluzione, tutte le altre soluzioni sono nella forma (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
per n
intero.
Pertanto vogliamo trovare un n
, dove x-n*b/gcd(a,b) >= 0
e y+n*a/gcd(a,b >= 0
. Dopo qualche trasformazione finiamo con le due disuguaglianze n >= -x*gcd(a,b)/b
e n >= y*gcd(a,b)/a
. Si noti che il simbolo della disuguaglianza potrebbe guardare nella direzione opposta a causa della divisione con un potenziale negativo a
o b
. Non mi interessa così tanto, dico semplicemente che un numero di -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
soddisfa definitivamente la disuguaglianza 1 e un numero di y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
soddisfa la disuguaglianza 2. C'è un n
, che soddisfa entrambe le disuguaglianze, anche uno dei 6 numeri.
Quindi calcolo le nuove soluzioni (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
per tutti e 6 i possibili valori di n
. E stampo la soluzione con il valore più basso più basso.
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
L'ordinamento in base all'ordine ordinato funziona nel modo seguente. Sto usando l'esempio2x + 3y = 11
Ordino ciascuna delle 6 soluzioni (queste sono chiamate chiavi) e le soluzioni originali in base alle loro chiavi:
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]
Questo ordina una soluzione completa non negativa alla fine (se ce n'è una).