Chủ Nhật, 17 tháng 2, 2019

[Pascal] Tìm đường đi ngắn nhất bằng thuật toán Dijkstra | Nguyễn Hoàng Huy

Giới thiệu: Thuật toán Dijkstra, mang tên của nhà khoa học máy tính người Hà Lan Edsger Dijkstra vào năm 1956 và ấn bản năm 1959, là một thuật toán giải quyết bài toán đường đi ngắn nhất nguồn đơn trong một đồ thị có hướng không có cạnh mang trọng số âm[1].
Bài toán:
Cho một đồ thị có hướng G = (V, E), một hàm trọng số w: E = [0; +∞) và một đỉnh nguồn s, đỉnh đích f. Cần tính toán được đường đi ngắn nhất từ đỉnh nguồn s đến đỉnh đích f.
Chúng ta dùng các đỉnh của đồ thị để mô hình các thành phố và các cạnh để mô hình các đường nối giữa chúng. Khi đó trọng số các cạnh có thể xem như độ dài của các con đường (và do đó là không âm). Chúng ta cần vận chuyển từ thành phố s đến thành phố f. Thuật toán Dijkstra sẽ giúp chỉ ra đường đi ngắn nhất chúng ta có thể đi.
Trọng số không âm của các cạnh của đồ thị mang tính tổng quát hơn khoảng cách hình học giữa hai đỉnh đầu mút của chúng. Ví dụ, với 3 đỉnh A, B, C đường đi A→B→C có thể ngắn hơn so với đường đi trực tiếp A→C.
Bộ dữ liệu:
Dữ liệu vào chứa các số n, m, s, f tương ứng với số đỉnh, số cạnh, đỉnh nguồn, đỉnh đích. m dòng tiếp theo chứa 3 số u, v, k với ý nghĩa là đường đi từ đỉnh u đến đỉnh v là k.
Dữ liệu ra là dãy các đỉnh là đường đi ngắn nhất từ đỉnh s đến đỉnh f.
Đây là một ví dụ:
Đồ thị ban đầu
Đường đi ngắn nhất là 1→5→6 với độ dài 25
Cài đặt:
Khai báo:
Mảng fr kiểu boolean để đánh dấu những đỉnh sẽ xét. fr[i] = True là đỉnh i chưa được xét.
Mảng d kiểu số nguyên chứa đường đi ngắn nhất hiện thời.
Mảng trace kiểu số nguyên lưu lại các đỉnh để sau này truy vết tìm đường đi ngắn nhất.
Khởi tạo:
Hai đỉnh không có đường đi được quy ước có độ dài là +∞; hai đỉnh trùng nhau có độ dài bằng không, có nghĩa là a[i, i] = 0.
d[s] được gán bằng 0, các đỉnh còn lại được gán là +∞.
Thiết kế:
Lặp mãi 3 câu lệnh 1, 2, 3 này cho đến khi có lệnh thoát:
1. Tìm đỉnh u = [1; n] mà d[u] là nhỏ nhất và u chưa bị đánh dấu.
2. Nếu u = 0 (không tìm thấy) hoặc u = f (đã tìm được đường đi ngắn nhất đến f) thì thoát vòng lặp.
3. Đánh dấu đỉnh u lại. Tìm đỉnh v = [1; n] mà a[u, v] > 0 (kề), d[v] > d[u] + a[u, v] (đường đi từ s→u + u→v có độ dài nhỏ hơn đường đi từ s→v) và v chưa được đánh dấu thì cập nhật: d[v] := d[u] + a[u, v], đồng thời gán trace[v] := u (v được đến từ u).
4. Truy vết tìm đường đi.
Chương trình:
Xem tại đây: http://mivi.pro/CANIW
[1]: https://vi.wikipedia.org/wiki/Thuật_toán_Dijkstra

Thứ Tư, 13 tháng 2, 2019

[Pascal] Tìm chu trình Euler | Nguyễn Hoàng Huy

Đề bài: Cho một đồ thị có n đỉnh và các cạnh nối. Tìm một chu trình Euler bắt đầu từ đỉnh 1 (đảm bảo đồ thị nhập vào có một chu trình Euler).
Input: có dạng như sau:
  • Dòng đầu chứa số đỉnh n và số m.
  • m dòng tiếp theo chứa 3 số nguyên u, v, k. Thể hiện giữa đỉnh u và đỉnh v có k cạnh nối.
Output: in ra một chu trình Euler tìm được, các đỉnh cách nhau bởi một dấu cách.
Ví dụ:
Input Output
3 3 1 2 1 3 2 3 1
1 2 2
2 3 2
3 1 2
Giải
Thuật toán để tìm chu trình Euler như sau:
Tạo mảng P để ghi đường đi và ngăn xếp S chứa các đỉnh để xét.
B1: Xếp vào S một đỉnh đầu tiên sẽ xét (ở đây là đỉnh 1)
B2: Xét đỉnh trên cùng của ngăn xếp S, giả sử đỉnh đó là u:
  • Nếu u là đỉnh cô lập thì lấy u ra khỏi ngăn xếp và thêm u vào P.
  • Nếu u kề với v (v là đỉnh đầu tiên trong tập đỉnh kề với u) thì đẩy v vào ngăn xếp, sau đó xóa bỏ số cạnh giữa u và v đi 1 đơn vị.
B3: Quay lại bước 2 cho tới khi ngăn xếp rỗng. Kết quả là chu trình Euler trong P theo thứ tự ngược lại.
Chương trình:
Xem tại đây: http://mivi.pro/lrWk1AH

Thứ Sáu, 8 tháng 2, 2019

[Pascal] Tìm Ma phương dạng 4n | Nguyễn Hoàng Huy

Đề bài: Một ma trận dạng 4n (với n ≥ 1) chứa các số từ 1 đến 4n2 được gọi là ma phương dạng 4n khi tổng S của các số trên từng dòng, trên từng cột và trên 2 đường chéo đều bằng nhau.
Ví dụ: Ma phương bậc 4 (n = 1) có dạng như sau:
Hình 1
Yêu cầu: Viết chương trình nhập vào số nguyên dương n (với n ≥ 1 và n ≤ 10), hãy xuất kết quả là ma phương dạng 4n ra màn hình có dạng: 4n dòng đầu tiên ghi 4n dòng của ma phương (trên mỗi dòng các số cách nhau bởi một khoảng cách); dòng 4n + 1 ghi giá trị tổng S.
Giải
Giải thuật để tìm ma phương dạng 4n (với n ≥ 1) như sau:
Bước 1: Chia ma trận ra thành từng ma trận nhỏ gồm 4 dòng và 4 cột (4 × 4)
Bước 2: Đánh số từ trái sang phải và từ trên xuống dưới vào các ô nằm trên đường chéo của từng ma trận nhỏ (như hình 2a).
Bước 3: Đánh số từ phải sang trái và từ dưới lên trên vào các ô còn lại (như hình 2b).
Hình 2a
Hình 2b
Tư tưởng: Theo hình 2, các ô nằm trên đường chéo là:
(1;1) (1;4) (1;5) (1;8) ...
(2;2) (2;3) (2;6) (2;7) ...
(3;2) (3;3) (3;6) (3;7) ...
(4;1) (4;4) (4;5) (4;8) ...
(5;1) (5;4) (5;5) (5;8) ...
Như vậy, các hàng thứ i có i chia hết cho 4 hoặc i-1 chia hết cho 4 thì sẽ có các ô (i; j) nằm trên đường chéo với j = {1; 4; 5; 8; 9; 12; 13; 16; ...}, các số trong tập này có quy luật là cộng 3 rồi cộng 1. Các hàng thứ i không thuộc trường hợp trên thì sẽ có các ô (i; j) nằm trên đường chéo với j = {2; 3; 6; 7; 10; 11; 14; 15; ...}, các số trong tập này có quy luật là cộng 1 rồi cộng 3. 
Dựa vào những điều trên, ta có thể đánh dấu những ô nằm trên đường chéo rồi điền số theo giải thuật nêu trên.
Chương trình:
Xem tại đây: http://mivi.pro/2jQHF6