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)
за допомогою розширеного алгоритму Евкліда.
Тоді я модифікую рішення (моє множення 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)
. Це можна зробити за допомогою розширеного алгоритму Евкліда. Ви можете отримати уявлення про те, як це працює у Вікіпедії . Різниця лише в тому, що замість 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
або обидва можуть бути негативними. Отже наша мета - перетворити їх на негативні.
Приємне в рівняннях Діофантіна полягає в тому, що ми можемо описати все рішення, використовуючи лише одне початкове рішення. Якщо (x,y)
це рішення, то всі інші рішення мають форму (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
для n
цілого числа.
Тому ми хочемо знайти n
, де 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
, яке задовольняє обидві нерівності, одне з 6 чисел також робить.
Тоді я обчислюю нові рішення (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
Я сортую кожне із шести рішень (це називаються ключами) та сортую оригінальні рішення за їх ключами:
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]
Це сортує повне негативне рішення до кінця (якщо є).