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
Itu monster.
Cobalah online: Peragaan . Format input adalahc\n[a,b]
dan format output [x,y]
.
Dalam hal tidak ada solusi integer, saya tidak akan mencetak apa pun, dan dalam hal tidak ada solusi integer alami, saya hanya akan mencetak solusi integer acak.
Penjelasan (Ikhtisar Kasar)
Pada awalnya saya akan menemukan solusi integer untuk persamaan ax + by = gcd(a,b)
dengan menggunakan algoritma Extended Euclidean.
Kemudian saya akan memodifikasi solusi (pengali a
dan b
dengan saya c/gcd(a,b)
) untuk mendapatkan solusi integer ax + by = c
. Ini berfungsi, jika c/gcd(a,b)
bilangan bulat. Kalau tidak, tidak ada solusi.
Semua solusi integer lainnya memiliki formulir a(x+n*b/d) + b(y-n*a/d) = c
dengan d = gcd(a,b)
untuk integer n
. Menggunakan dua ketidaksetaraan x+n*b/d >= 0
dan y-n*a/d >= 0
saya bisa menentukan 6 nilai yang mungkin untuk n
. Saya akan mencoba semuanya dan mencetak solusinya dengan koefisien terendah tertinggi.
Penjelasan (Detail)
Langkah pertama adalah menemukan solusi integer untuk persamaan tersebut ax' + by' = gcd(a,b)
. Ini dapat dilakukan dengan menggunakan algoritma Euclidean yang diperluas. Anda bisa mendapatkan ide tentang cara kerjanya di Wikipedia . Satu-satunya perbedaan adalah, bahwa alih-alih menggunakan 3 kolom ( r_i s_i t_i
) saya akan menggunakan 6 kolom ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
). Dengan cara ini saya tidak harus menyimpan dua baris terakhir dalam memori, hanya yang terakhir.
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.
Sekarang saya ingin mencari solusinya ax + by = c
. Ini hanya mungkin, ketika c mod gcd(a,b) == 0
. Jika persamaan ini puas, saya hanya mengalikan x',y'
dengan 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]
Kami memiliki solusi integer untuk ax + by = c
. Perhatikan, bahwa x
, y
atau keduanya mungkin negatif. Jadi tujuan kami adalah mengubahnya menjadi non-negatif.
Hal yang menyenangkan tentang persamaan Diophantine adalah, kita dapat menggambarkan semua solusi hanya dengan menggunakan satu solusi awal. Jika (x,y)
solusi, bahwa semua solusi lainnya adalah dari bentuk (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
untuk n
integer.
Karena itu kami ingin mencari n
, di mana x-n*b/gcd(a,b) >= 0
dan y+n*a/gcd(a,b >= 0
. Setelah beberapa transformasi kita berakhir dengan dua ketidaksetaraan n >= -x*gcd(a,b)/b
dan n >= y*gcd(a,b)/a
. Perhatikan bahwa simbol ketimpangan mungkin melihat ke arah lain karena pembagian dengan potensi negatif a
atau b
. Saya tidak terlalu peduli tentang hal itu, saya hanya mengatakan bahwa satu angka -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
pasti memuaskan ketidaksetaraan 1, dan satu angka y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
memuaskan ketidaksetaraan 2. Ada n
, yang memenuhi kedua ketidaksetaraan, salah satu dari 6 angka juga.
Lalu saya menghitung solusi baru (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
untuk semua 6 nilai yang mungkin dari n
. Dan saya mencetak solusinya dengan nilai terendah tertinggi.
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
Urutkan berdasarkan urutan pesanan mereka berfungsi dengan cara berikut. Saya menggunakan contohnya2x + 3y = 11
Saya mengurutkan masing-masing dari 6 solusi (ini disebut kunci), dan mengurutkan solusi asli dengan kunci mereka:
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]
Ini semacam solusi non-negatif lengkap sampai akhir (jika ada).