Thuật Toán Euclid Mở Rộng – Extended Euclid Algorithm
Có thể bạn quan tâm
Tác giả: Huỳnh Văn Duy
Có thể nói trong lập trình tính toán thì các bài toán về số học chiếm một phần khá lớn. Trong đó, một trong những thuật toán được biết đến nhiều nhất là Giải thuật euclid mở rộng, thuật toán này có thể giải quyết rất nhiều bài toán liên quan đến số học. Nên hôm nay chúng ta sẽ tìm hiểu về nó.
ĐẦU TIÊN TA CẦN TÌM HIỂU MỘT CHÚT VỀ THUẬT TOÁN EUCLID NGUYÊN THỦY
Lịch sử thuật toán Euclid:
Thuật toán Euclid là một trong những thuật toán cổ nhất được biết đến, từ khi nó xuất hiện trong cuốn Euclid’s Elements khoảng năm 300 trước công nguyên. Euclid khởi đầu đã trình bày rõ ràng vấn đề về phương diện hình học, như vấn đề tìm ra một thước đo chung cho độ dài hai đường thẳng, và thuật toán của ông đã xử lý bằng cách lặp lại phép trừ đoạn dài hơn cho đoạn ngắn hơn. Tuy nhiên, thuật toán đã hầu như không được phát hiện ra bởi Euclid và nó đã có thể được biết đến sớm hơn 200 năm. Nó cũng đã được biết đến bởi Eudoxus of Cnidus (khoảng năm 375 trước công nguyên) và Aristotle (khoảng năm 330 trước công nguyên).
Mô tả thuật toán:
Cho 2 số tự nhiên a và b, không đồng thời bằng 0: kiểm tra nếu b bằng 0, thì a là ước chung lớn nhất (UCLN). Nếu không, lặp lại xử lý sử dụng b và phần còn lại sau khi lấy a chia cho b. Phần còn lại sau khi chia a cho b thường được viết là a mod b.
Các thuật toán này có thể sử dụng trong bất kì hoàn cảnh nào khi còn phần dư. Điều này bao gồm các nhóm đa thức như nhóm số nguyên Gauxơ. Thuật toán không chỉ áp dụng cho số tự nhiên mà còn áp dụng cho nhiều trường hợp tổng quát khác sẽ được mô tả chi tiết sau.
Thuật toán có thể được cài đặt rất đơn giản:
#include <iostream> #include <algorithm> using namespace std; #define builtin_gcd __gcd int gcd(int a, int b) { if(b==0) return a; else return gcd(b,a%b); } int main() { cout << gcd(252,105) << endl; cout << builtin_gcd(252,105) << endl; return 0; }Dĩ nhiên, ngôn ngữ lập trình C++ cũng cung cấp cho chúng ta một hàm có sẵn để tìm ước chung lớn nhất của hai số bằng thuật toán euclid, đó là hàm __gcd(a, b) sẽ trả về ước chung lớn nhất của hai số a và b.
THUẬT TOÁN EUCLID MỞ RỘNG
Phương trình diophantine: (1)
Theo định lí Bézout (Bézout’s indentify): Cho hai số nguyên a, b khi đó luôn tồn tại hai số x, y sao cho:
Người ta cũng chứng minh được phương trình trên có nghiệm khi và chỉ khi gcd(a, b) = c. Và như thế có nghĩa là phương trình diophante có thể có vô số nghiệm, và từ mỗi một nghiệm ta có thể sinh ra những nghiệm khác.
Định nghĩa số nguyên k sao cho: . Chia vế theo vế phương trình cho ta được phương trình mới
(2)
Dễ thấy và chính là một nghiệm của phương trình (1). Giả sử là một nghiệm khác của phương trình (1), ta có:
Suy ra: (3), nghĩa là a là ước của , và là ước của . Nên ta có: với r là một số nguyên. Thay vào (3), ta được:
Trong đó:
hay
Như vây, nếu có một nghiệm bất kì thì tất cả các nghiệm sẽ có dạng:
Ví dụ: Tìm tất cả các nghiệm của phương trình .
- Đầu tiên, ta xét , vì nên phương trình chắc chắn có nghiệm.
- Áp dụng thuật toán Euclid, ta có:
- Bây giờ, ta tìm cách biểu diễn 3 bằng một mối quan hệ tuyến tính giữa 258 và 147. Dựa vào trên, ta có:
- Tiếp theo, ta viết , và nhân phương trình cho 123 vì . Ta được:
- .
- Vậy một nghiệm của phương trình là: , và các nghiệm khác có dạng:
Cài đặt cụ thể:
// Extended euclid solve diophantine linear equation #include <bits/stdc++.h> #define x first #define y second using namespace std; typedef long long ll; typedef pair<int, int> ii; ll a, b, c; ii extended_gcd(ll a, ll b) { if (b == 0) return ii(1, 0); ii qr = ii(a / b, a % b); ii st = extended_gcd(b, qr.y); return ii(st.y, st.x - qr.x*st.y); } void extended_gcd2(ll a, ll b, ll &X, ll &Y) { // another version ll d = __gcd(a, b); ll m = a, n = b; ll xm = 1; // (ym = 0) m = a = a*1 + b*0 ll xn = 0; // (yn = 1) n = a = a*0 + b*1 while (n) { ll q = m / n; ll r = m - q*n; ll xr = xm - q*xn; m = n, xm = xn; n = r, xn = xr; } X = xm * (c/d); Y = ((d - a*xm) / b) * (c/d); } int main() { freopen("in.txt", "r", stdin); scanf("%lld %lld %lld", &a, &b, &c); ll d = __gcd(a, b); ii ex = extended_gcd(a, b); printf("%lld %lldn", c/d*ex.x, c/d*ex.y); ll X, Y; extended_gcd2(a, b, X, Y); printf("%lld %lldn", X, Y); assert(c/d*ex.x == X && c/d*ex.y == Y); return 0; }NGHỊCH ĐẢO MODULO
Một trong những ứng dụng quan trọng nhất của thuật toán Euclid mở rộng đó chính là dùng để tìm nghịch đảo modulo: Nhận xét: nếu , giải phương trình
Ta có:
Khi đó được gọi là nghịch đảo của a theo modulo m (ký hiệu )
Ví dụ: a = 7, m = 10, Xét phương trình
Nghiệm
Khi đó:
TỔNG KẾT:
- Thuật toán Euclid mở rộng có thể dùng để giải phương trình Diophantine
- Họ nghiệm của phương trình Diophantine khi đã có nghiệm x, y là:
BONUS: ĐỊNH LÍ THẶNG DƯ TRUNG HOA (CHINESE REMAINDER THEOREM)
Định lý thặng dư Trung Hoa là tên người phương tây đặt cho định lý này. Người Trung Hoa gọi nó là bài toán Hàn Tín điểm binh. Hàn Tín là một danh tướng thời Hán Sở, từng được phong tước vương thời Hán Cao Tổ Lưu Bang đang dựng nghiệp. Sử ký Tư Mã Thiên viết rằng Hàn Tín là tướng trói gà không nổi, nhưng rất có tài quân sự. Tục truyền rằng khi Hàn Tín điểm quân số, ông cho quân lính xếp hàng 3, hàng 5, hàng 7 rồi báo cáo số dư. Từ đó ông tính chính xác quân số đến từng người.
Gần đây, định lý số dư Trung Quốc có nhiều ứng dụng trong các bài toán về số nguyên lớn áp dụng vào Lý thuyết mật mã. – Wikipedia
Bản chất của bài toán Hàn Tín điểm binh là giải phương trình đồng dư bật nhất được mô tả tổng quát như sau:
Cho các số nguyên:
- : đôi một nguyên tố cùng nhau
- Tìm sao cho:
Đặt:
- Nhận xét:
- Tính
Chỉ ra một nghiệm:
- với mọi do
- do
- với mọi j.
- Họ nghiệm:
Tài liệu tham khảo:
- How to find solutions of linear Diophantine ax + by = c?
- Extended Euclid Slide – Lê Minh Hoàng
- A tutorial on the Extended Euclid’s Algorithm
Chia sẻ bài viết này
- Nhấn vào chia sẻ trên Facebook (Mở trong cửa sổ mới)
- Bấm để chia sẻ trên Twitter (Mở trong cửa sổ mới)
- Thêm
- Bấm để gửi một liên kết tới bạn bè (Mở trong cửa sổ mới)
- Bấm để in ra (Mở trong cửa sổ mới)
- Bấm để chia sẻ lên LinkedIn (Mở trong cửa sổ mới)
- Bấm để chia sẻ lên Reddit (Mở trong cửa sổ mới)
- Bấm để chia sẻ trên Tumblr (Mở trong cửa sổ mới)
- Bấm để chia sẻ trên Pinterest (Mở trong cửa sổ mới)
- Bấm để chia sẻ trên Pocket (Mở trong cửa sổ mới)
- Nhấp để chia sẻ trên Telegram (Mở trong cửa sổ mới)
- Nhấp để chia sẻ trên WhatsApp (Mở trong cửa sổ mới)
Có liên quan
Từ khóa » Thuật Toán ơ Cơ Lít Mở Rộng
-
Thuật Toán Euclid Mở Rộng, Nghịch đảo Modulo, Và Định Lý Số Dư ...
-
Giải Thuật Euclid Mở Rộng – Wikipedia Tiếng Việt
-
Hiểu Thuật Toán Euclid Mở Rộng Trong 5 Phút - YouTube
-
Thuật Toán Euclide Mở Rộng - VNOI
-
Bài 4: Giải Thuật Euclid Và Euclid Mở Rộng - Blog Nam Phạm
-
Thuật Toán Euclide Mở Rộng - Nguyễn Đức Cương
-
Thuật Toán Euclid
-
Lý Thuyết Số Về Thuật Toán Oclit - TaiLieu.VN
-
Áp Dụng Thuật Toán Ơ-clit để Tìm ƯCLN Của: 126 Và 162 - Haylamdo
-
Cách Tính ước Chung Lớn Nhất Và Nghịch đảo Modulo - Viblo
-
THUẬT TOÁN ƠCLIT TÌM ƯCLN, BCNN - Tài Liệu Text - 123doc
-
Mat Ma Pho Thong - Tài Liệu Text - 123doc
-
Thuật Toán Tìm ước Chung Lớn Nhất Trong C/C++