Cài đặt chương trình và minh họa kết quả --- 225.1 Cấu trúc dữ liệu và giải thuật --- 225.2 Cấu trúc dữ liệu --- 245.3 Giải thuật ---255.4 Minh họa kết quả --- 26LỜI MỞ ĐẦUMôn Đại Số Tuy
Các định nghĩa cơ bản về lí thuyết đồ thị
1 Đơn đồ thị vô hướng
+ Đơn đồ thị vô hướng : G = , gồm V là tập các đỉnh, E là tập các cặp không có thứ tự gồm hai phần tử khác nhau của V gọi là các cạnh
2.Đa đồ thị vô hướng
+ Đa đồ thị vô hướng G = , gồm V là tập các đỉnh, E là họ các cặp không có thứ tự gồm hai phần tử khác nhau của V gọi là các cạnh Hai cạnh e1, e2 được gọi là cạnh bội nếu chúng cùng tương ứng với 1 cặp đỉnh
3.Đơn đồ thị có hướng
+ Đơn đồ thị có hướng :G = , gồm V là tập các đình, E là tập các cặp có thứ tự gồm hai phần tử V gọi là các cung
4.Đa đồ thị có hướng
+ Đa đồ thị có hướng G = , gồm V là tập các đỉnh, E là họ các cặp có thứ tự gồm hai phần tử V gọi là các cung Hai cung e1, e2 tương ứng với cùng một cặp đình được gọi là cung lặp
+ Hai đỉnh u, v được gọi là 2 đỉnh kề nếu tồn tại cạnh e = (u, v) là cạnh của đồ thị 6.Cạnh liên thuộc
+Nếu cạnh e = (u, v) là cạnh của đồ thị thì cạnh e được gọi là cạnh liên thuộc với 2 đỉnh u, v.
+Bậc của đỉnh u trên đồ thị vô hướng là số cạnh liên thuộc với đỉnh u, ký hiệu deg (u). Đỉnh có bậc 0 được gọi là đình cô lập.
+ Dây các đỉnh (hoặc dãy các cạnh) trong đó 2 đình liên tiếp có cạnh nổi. Độ dài đường đi là số cạnh trên đường đi.
+Là đường đi gồm các cạnh phân biệt có đỉnh đầu trùng đỉnh cuối.
+Đồ thị vô hướng được gọi là liên thông nếu luôn tìm được đường đi giữa 2 đỉnh bất kỳ của đồ thị.
+Ngoại trừ đỉnh đầu với đỉnh cuối trùng nhau, không còn 2 đỉnh nào giống nhau. 12.Liên thông mạnh
+Đồ thị có hướng gọi là liên thông mạnh, nếu giữa 2 đỉnh bất kỳ u, v luôn có đường đi từ u tới v.
+Đồ thị có hướng gọi là liên thông yếu nếu đồ thị vô hướng tương ứng của nó liên thông
Ví dụ 1.1 Tìm các đường đi, chu trình trong đồ thị vô hướng như hình 1.1 b c d a e f
Hình 1.1 Đường đi trên đồ thị
+ a, b, c, d là đường đi đơn độ dài 3.
+ a, b, f, không là đường đi vì (b, f) không phải là cạnh của đồ thị.
+ Dãy a, b, c, f, e, a là chu trình độ dài 5.
+ Đường đi a, b, c, f, e, b, c có độ dài 6 không phải là đường đi đơn vì cạnh
Ví dụ 1.2 Kiểm tra tính liên thông của đồ thị hình 1.2 e f Đồ thị này không liên thông vì có đỉnh g là đỉnh cô lập nên không có đường đi từ đình bất kỳ đến đỉnh g. b c d a e f g
Hình 1.2 Đồ thị không liên thông
Khái niệm Chu trình Euler, Đường đi Euler và Đồ thị Euler
Cho đồ thị vô hướng G=(V,E).
Chu trình Euler là chu trình đi qua mọi cạnh và mọi đỉnh của đồ thị, mỗi cạnh không đi quá 1 lần. Đường đi Euler là đường đi qua mọi cạnh và mọi đỉnh của đồ thị, mỗi cạnh không đi quá 1 lần.
Cho đồ thị có hướng G=(V,E).
Chu trình có hướng Euler là chu trình có hướng đi qua mọi cung và mọi đỉnh đồ thị, mỗi cung không đi quá 1 lần. Đường đi có hướng Euler là đường đi có hướng đi qua mọi cung và mọi đỉnh đồ thị, mỗi cung không đi quá 1 lần. Đồ thị chứa chu trình Euler gọi là Đồ thị Euler.
Ví dụ 1.3 Đồ thị hình 1.3 có chu trình Euler (1, 2, 4, 3, 6, 5, 2, 3, 1)
Hình 1.3 Đồ thị có chu trình Euler Điều kiện cần và đủ: Định lý 1 (Định lý Euler): Đồ thị G có chu trình Euler khi và chỉ khi G liên thông và mọi đỉnh có bậc chẵn khác 0. Định lý 2 Cho đồ thị G có k đỉnh bậc lẻ Khi đó số đường đi tối thiểu phủ G là k/2 Đồ thị luôn có số đỉnh bậc lẻ là chẵn, k=2n.
Thuật toán Fleury tìm chu trình Euler
Đầu vào Đồ thị G ≠∅, không có đỉnh cô lập. Đầu ra Chu trình Euler C của G, hoặc kết luận G không có chu trình Euler
-Chọn đỉnh xuất phát bất kỳ v0 Đặt v1:= v0, C := (v0) H := G.
(2) Nếu H = ∅ , thì kết luận C là chu trình Euler, kết thúc Ngược lại sang bước (3).
-Trường hợp đỉnh v1là đỉnh treo: Tồn tại duy nhất đỉnh v2kề v1 Chọn cạnh (v1, v2) Sang bước (4).
-Trường hợp đỉnh v1không là đỉnh treo:
Nếu mọi cạnh liên thuộc v1là cầu, thì không có chu trình Euler, kết thúc.
-Ngược lại, chọn cạnh( v1,v2) bất kỳ không phải là cầu trong H Thêm vào đường đi đỉnh v2 Sang bước (4)
(4)Xoá cạnh vừa đi qua, và xoá đỉnh cô lập:
Loại khỏi H cạnh ( v1,v2) Nếu H có đỉnh cô lập, thì loại chúng khỏi H Đặt v1:=v2. Sang bước (2)
Ví dụ 1.4 Cho G là đồ thị hình sau:
Hình 1.4 Đồ thị liên thông và có các đỉnh bậc chẵn.
+Nếu xuất phát từ đỉnh 1, có hai cách đi tiếp: hoặc sang 2 hoặc sang 3, giả sử ta sẽ sang 2 và xoá cạnh (1, 2) vừa đi qua Từ 2 có ba cách để đi, là sang 3 sang 4 hoặc sang 5, giả sử ta sẽ sang 5 và xoá cạnh (2, 5) vừa đi qua Từ đỉnh
5, chỉ có 1 cách đi là sang đỉnh 6, nên cho dù (5, 6) là cầu ta cũng phải đi sau đó xoá luôn cạnh (5, 6) Từ đỉnh 6, chỉ có 1 cách đi là sang đỉnh 3, nên cho dù (6, 3) là cầu ta cũng phải đi sau đó xoá luôn cạnh (6, 3) Đến đây, các cạnh còn lại của đồ thị có thể vẽ như Hình bằng nét liền, các cạnh đã bị xoá được vẽ bằng nét đứt.
Hình 1.5 Duyệt đồ thị theo thuật toán Fleury
Bây giờ đang đứng ở đỉnh 6 thì ta có 3 cách đi tiếp: sang 1, sang 2 hoặc sang
4 Vì (3, 1) là cầu nên ta sẽ không đi theo cạnh (3, 1) mà sẽ đi (3, 4) hoặc (3,
2) Nếu đi theo (3, 4) và cứ tiếp tục đi như vậy, ta sẽ được chu trình Euler là Còn đi theo (3, 2) sẽ tìm được chu trình Euler là: .
Một số thuật toán trên Đồ thị
*Thuật toán Floyed tìm đường đi ngắn nhất giữa mọi cặp đỉnh trên đồ thị:
Thuật giải tìm độ dài đường đi ngắn nhất giữa mọi cặp đỉnh trong đồ thị có hướng liên thông có trọng số (không bắt buộc ≥0). Đầu vào Đồ thị liên thông G=(V,E), V= {1, 2, , n}, có trọng số w(i,j) với mọi cung (i,j). Đầu ra Ma trận D=[d(i,j)], trong đó d(i,j) là chiều dài đường đi ngắn nhất từ i đến j với mọi cặp (i,j).
Bước khởi tạo: Ký hiệu D0là ma trận xuất phát D0= [d0(i,j)]
Trong đó: d0(i,j) = w(i,j) nếu tồn tại cung (i,j) và d0(i,j) = + nếu không tồn tại cung (i,j) (đặc biệt nếu không có khuyên tại i thì d0(i,i) =+ ).
Kiểm tra kết thúc: Nếu k = n, kết thúc.
D = Dn là ma trận độ dài đường đi ngắn nhất Ngược lại tăng k lên 1 đơn vị (k:=k+1) và sang (3).
Tính ma trận Dktheo Dk-1:
Với mọi cặp (i,j), i=1 n, j=1 n thực hiện:
Nếu dk-1(i,j) > dk-1(i,k) + dk-1(k,j) thì đặt dk(i,j) := dk-1(i,k) + dk-1(k,j) ngược lại đặt dk(i,j) := dk-1(i,j) Quay lại bước (2). Định lý 1 :Thuật toán Floyd là đúng.
Nếu ma trận kết quả của thuật toán Floyd có phần tử hữu hạn trên đường chéo i = i thì đồ thị chứa chu trình.
Nếu ma trận kết quả chứa phần tử +∞ ngoài đường chéo i = i thì đồ thị không liên thông mạnh.
Ghi chú: Từ hệ quả trên ta có thể sử dụng thuật toán Floyd, với w(i, j) = 1 nếu tồn tại cung (i, j) và w(i, j)= +∞ nếu không tồn tại cung (i, j), để xác định xem đồ thị có chu trình hay có liên thông hay không.
Ví dụ 1.6 Xét đồ thị có hướng hình 1.6
4 5 6 Áp dụng thuật toán Floyd ta có:
Ma trận khoảng cách xuất phát D 0 là (các ô trống là )
Bảng 1.7 Biểu diễn đồ thị cần tìm bằng thuật toán Floyd bằng ma trận Đỉnh 1 2 3 4 5 6
Từ ma trận D0, theo thuật toán, ta xây dựng các ma trận tiếp theo như sau (các ô gạch dưới có giá trị thay đổi)
Bảng 1.8 Các bước tìm đường đi ngắn nhất giữa mọi cặp đỉnh bằng Floyd
Cuối cùng, D6là ma trận khoảng cách ngắn nhất giữa các đỉnh Theo hệ quả ta thấy đồ thị liên thông chứa mạnh và chu trình
THUẬT TOÁN TÌM 1 CHU TRÌNH EULER TỪ 1 ĐỈNH BẤT KÌ
import numpy as np n = int(input('Nhập số đỉnh của đồ thị: ')) adj = [[] for _ in range(n)] #tạo 1 ds kề adj với n phần tử để chứa các đỉnh kề degree = [0] * n #Tạo một danh sách để lưu chữ bậc của đỉnh print("Nhập ma trận kề (mỗi hàng cách nhau một dấu cách):") a = np.array([input().split() for _ in range(n)], dtype=int)
#Lệnh để tạo nên danh sách kề và bậc của đỉnh for i in range(n): for j in range(n): if a[i][j] == 1: adj[i].append(j) degree[i] += 1 print('Danh sách kề của mỗi đỉnh:') for i in range(n): print(f'Đỉnh {i}: {adj[i]}') print('Bậc của đỉnh là:') for i in range(n): print(f'Bậc của đỉnh {i}: {degree[i]}') Đỉnh 1 2 3 4 5 6
#Tạo ngăn xếp rỗng để lưu trữ các đỉnh trong quá trình tìm kiếm st = []
#Tạo danh sách rỗng để lưu chữ chu trình euler
#Định nghĩa 1 hàm euler để tìm chu trình euler def euler(v): st.append(v) while st: i = st[-1] if adj[i]: j = adj[i][0] st.append(j) adj[i].remove(j) adj[j].remove(i) else: st.pop()
EC.reverse() v = int(input('Nhập đỉnh xuất phát: ')) visited = [False] * n dfs(v, visited, adj)
#Điều kiện để là chu trình euler if (all(degree[i] % 2 == 0 for i in range(n))) and all(visited): euler(v) print('Chu trình Euler là:') for i in EC: print(i, end=' ') else: print('Đồ thị không có chu trình Euler')
Khái niệm đường đi, chu trình Hamilton
Cho đồ thị G = (V, E) có n đỉnh.
Chu trình (x 1 , x 2 , , x n , x 1 ) được gọi là chu trình Hamilton nếu x i ≠ x j với 1 ≤ i < j ≤ n Đường đi (x 1 , x 2 , , x n ) được gọi là đường đi Hamilton nếu x i ≠ x j với 1 ≤ i < j ≤ n
Chúng ta có thể phát biểu lại như sau:
+ Chu trình Hamilton là chu trình xuất phát từ 1 đỉnh, đi thăm tất cả những đỉnh còn lại mỗi đỉnh đúng một lần, cuối cùng quay trở lại với đỉnh xuất phát.
+ Đường đi Hamilton là đường đi qua tất cả các đỉnh của đồ thị, mỗi đỉnh đúng một lần.
Khác với khái niệm chu trình Euler và đường đi Euler, một chu trình Hamilton không phải là đường đi Hamilton bởi có đỉnh xuất phát được thăm tới 2 lần.
Ví dụ: Xét 3 đơn đồ thị G1, G2, G3sau: Đồ thị G1 có chu trình Hamilton (a, b, c, d, e, a) G2 không có chu trìnhHamilton vì deg(a) = 1 nhưng có đường đi Hamilton (a, b, c, d) G3không có cả chu trình Hamilton lẫn đường đi Hamilton.
Các định lí cơ bản
Điều kiện cần
Giả sử đồ thị G có chu trình Hamilton C Khi đó: i) Đồ thị G liên thông. ii) Mọi đỉnh của G lớn hơn hoặc bằng 2 và có đúng hai cạnh liên thuộc thuộc chu trình C. iii) Nếu xóa đi k đỉnh bất kỳ cùng các cạnh liên thuộc chúng thì đồ thị còn lại sẽ có tối đa k thành phần liên thông.
Giả sử đồ thị n đỉnh G có đường đi Hamilton P Khi đó:
(ii) Có ít nhất n – 2 đỉnh bậc ≥ 2 và mỗi đỉnh có đúng hai cạnh liên thuộc thuộc đường đi P.
(iii) Nếu xóa đi k đỉnh bất kỳ cùng các cạnh liên thuộc chúng thì đồ thị còn lại sẽ có tối đa k + 1thành phần liên thông.
Điều kiện đủ
* Định lớ 1: Đồ thị đủ Kn với n lẻ n ≥3 cú n – ẵ chu trỡnh Hamilton từng đụi một không giao nhau.
* Định lý 2 ( Dirac) : Cho G là đơn đồ thị n đỉnh (n ≥ 3) Nếu bậc deg(v) ≥ n/2 với mọi đỉnh vcủa G thì G có chu trình Hamilton.
* Định lý 3: Cho G là đồ thị đơn nđỉnh (n ≥ 3) Nếu bậc d(v) ≥ (n-1)/2với mọi đỉnh v của G thì G có đường đi Hamilton.
* Định lý 4 : Cho G là đồ thị đơn n đỉnh (n≥3) Giả sử u và v là 2 đỉnh không kề nhau của G sao cho deg(u) + deg(v) ≥ n
Khi đó G có chu trình Hamilton khi và chỉ khi đồ thị G + (u,v) có chu trình Hamilton.
* Định lý 5 : Cho G là đồ thị đơn giản nđỉnh Giả sử G’ và G’’ là 2 đồ thị thu được từ G bằng cách quy nạp nối tất cả các cặp đỉnh không kề nhau có tổng các bậc ít nhất bằng n Khi đó ta có G’ = G’’.
Từ định nghĩa trên ta có thể định nghĩa khái niệm bao đóng của đồ thị
* Bao đóng : C(G) của đồ thị G nđỉnh là đồ thị thu được từ G bằng cách, theo quy nạp, nối tất cả các cặp đỉnh không kề nhau mà tổng số bậc ít nhất bằngncho đến khi không còn cặp đỉnh nào như vậy nữa.
* Định lý 6: Đồ thị G có chu trình Hamilton khi và chỉ khi bao đóng của G có chu trình Hamilton.
* Định lý 7: Nếu bao đóng C(G) = Kn(n 3) thì đồ thị G có chu trình Hamilton.
* Định lý 8 ( Định lý Ore): Cho G là đơn đồ thịnđỉnh(n 3).
Nếu deg(u) + deg(v) nvới mọi cặp đỉnh không kề nhau thì đồ thị G có chu trình Hamilton.
* Định lý 9 : Cho G là đơn đồ thị n đỉnh (n 3) và m cạnh Nếu m C(n-1,2) + 2 thì đồ thị G có chu trình Hamilton.
* Định lý 10: Cho đồ thị G là đồ thị lưỡng phân với 2 tập đỉnh V1và V2sao cho card(v1) = card(v2) = n ≥ 2 Nếu deg(v) > n/2với mọi đỉnh v của G thì G có chu trình Hamilton.
* Định lý 11: Đồ thị Km,ncó chu trình Hamilton khi và chỉ khim = n.
* Định lý 12: Đồ thị Km,ncó đường đi Hamilton khi và chỉ khi |m-n|=1
Đồ thị có hướng
* Định lý 13:(Điều kiện đủ tồn tại chu trình có hướng Hamilton) a (Meyniel) Nếu đồ thị G liên thông mạnh và deg(u) + deg(v) ≥ 2n - 1, u, v G không kề nhau thì G có chu trình có hướng Hamilton b (Ghoula – Houri) Nếu đồ thị G liên thông mạnh và deg(v) n v G thì G có chu trình có hướng Hamilton. c (Woodall) Nếu deg 0 (u) + deg 1 (v) n u, v G không tồn tại cung từutừ v thì G có chu trình có hướng Hamilton d Nếu deg 1 (v) n/2 & deg 0 (v) n/2 v G thì G có chu trình có hướng Hamilton.
* Định lý 14: (Điều kiện đủ tồn tại đường đi có hướng Hamilton) a Nếudeg(u) + deg(v) 2n - 3 u, v G không kề nhau thì G có đường đi có hướng Hamilton. b Nếu deg(v) n - 1 v G thì G có đường đi có hướng Hamilton. c Nếudeg 0 (u) + deg 1 (v) n – 1 u, v G không tồn tại cung từuđếnv thì G có đường đi có hướng Hamilton. d Nếu deg 1 (v) n/2 & deg 0 (v) n/2 v G thì G có đường đi có hướng Hamilton. Bây giờ chúng ta nghiên cứu đường đi và chu trình có hướng Hamilton trong đồ thị có hướng đủ (có đồ thị lót đủ) Trước hết là định lý khẳng định sự tồn tại đường đi có hướng Hamilton trong đồ thị có hướng đủ.
* Định lý 15: (Konig) Mọi đồ thị có hướng đủ đều có đường đi có hướng Hamilton.
* Định lý 16: Đồ thị có hướng đủ G = (V, E) gọi là bắc cầu nếu(u, v) và(v, w) E suy ra(u, w) E.
Từ định nghĩa ta thấy ngay, một đồ thị có hướng đủ là bắc cầu khi và chỉ khi nó không có chu trình có hướng độ dài 3.
* Định lý 17: Đồ thị có hướng đủ bắc cầu khi và chỉ khi nó không có chu trình có hướng.
* Định lý 18: Đường đi Hamilton trong đồ thị có hướng đủ là duy nhất khi và chỉ khi đồ thị bắc cầu.
* Định lý 19: (Moon – Moser)Cho G = (V, E) là đồ thị có hướng đủ liên thông mạnh bậc n (n 3) Khi đó với mọi đỉnhv và số nguyênp (3 p n) luôn tồn tại chu trình có hướng sơ cấp độ dàipqua đỉnhv.
* Định lý 20: (Camion) Đồ thị có hướng đủ có chu trình có hường Hamilton khi và chỉ khi nó liên thông mạnh.
Thuật toán quay lui giải bài toán người giao hàng
Thuật toán quay lui
Thuật toán quay lui là một phương pháp lập trình để giải quyết các vấn đề một cách hệ thống bằng cách chia nhỏ chúng thành các bài toán con nhỏ hơn Phương pháp này thường được sử dụng trong các bài toán tối ưu hóa và các bài toán quyết định
Bài toán người giao hàng
Một người giao hàng cần phải giao hàng đến m địa điểm khác nhau trong một thành phố Mỗi địa điểm cần được thăm đúng một lần, và sau đó người giao hàng cần quay trở lại điểm xuất phát ban đầu Mục tiêu là xác định trình tự giao hàng sao cho tổng khoảng cách di chuyển là ngắn nhất Khoảng cách giữa hai địa điểm có thể được hiểu là cự li địa lý, thời gian di chuyển, hoặc chi phí phát sinh, và được xem là đã biết trước.
Giả sử có ma trận chi phí C=c ij với i,j=1,2,…m , trong đó cij là chi phí di chuyển từ địa điểm i đến địa điểm j Hành trình của người giao hàng có thể được biểu diễn như một chuỗi các cặp: (v(1),v(2)),(v(2),v(3)),…,(v(m-1),v(m)),(v(m),v(1)) với v(i) là địa điểm thứitrong hành trình.
Ta xét đồ thị đầy đủ G=(V,E) với V={1,2…m} ,có trọng số trên các cạnh cij,nghĩa là giữa mọi cặp địa điểm i và j với i≠j, luôn có cạnh nối (i,j) và (j,i) trong đồ thị Bài toán trở thành việc tìm chu trình Hamilton có tổng chi phí là nhỏ nhất trên đồ thị G, với chu trình Hamilton là một chu trình đi qua mỗi đỉnh đúng một lần và quay về điểm xuất phát
Cách giải bài toán người giao hàng
Ma trận chi phí C: Đây là ma trận đã cho, nơi C[i][j] biểu diễn chi phí di chuyển từ địa điểm i đến địa điểm j.
-Mảng đường đi: Một mảng để lưu trữ đường đi hiện tại.
-Biến chi phí tối ưu: Một biến để lưu trữ chi phí tối ưu nhất tìm được.
-Mảng đánh dấu: Một mảng để đánh dấu các địa điểm đã được thăm.
Bước 2: Định nghĩa Hàm Quay Lui
Hàm quay lui sẽ thực hiện các nhiệm vụ sau:
-Kiểm tra điều kiện dừng: Nếu tất cả các địa điểm đã được thăm, kiểm tra xem chi phí trở về điểm xuất phát có thấp hơn chi phí tối ưu hiện tại không Nếu có, cập nhật chi phí tối ưu.
-Lặp qua các địa điểm: Với mỗi địa điểm chưa được thăm, thực hiện các bước sau: -Đánh dấu địa điểm đó là đã thăm.
-Thêm chi phí di chuyển đến địa điểm đó vào chi phí hiện tại.
-Gọi đệ quy hàm quay lui với địa điểm mới.
-Khi trở về từ đệ quy, bỏ đánh dấu và trừ bớt chi phí tương ứng.
-Quay lui: Quay lại bước trước để thử các khả năng khác.
Bước 3: Chạy Hàm Quay Lui
-Bắt đầu từ một địa điểm (thường là địa điểm xuất phát).
Sau khi hàm quay lui hoàn thành, in ra đường đi và chi phí tối ưu.
Ứng dụng của bài toán Người giao hàng
Bài toán người giao hàng sử dụng chu trình Hamilton là một bài toán nổi tiếng trong lĩnh vực tối ưu hóa và lý thuyết đồ thị Mục tiêu của bài toán này là tìm ra một chu trình (đường đi qua mỗi đỉnh một lần và trở về điểm xuất phát) có tổng chi phí
(thường là khoảng cách hoặc thời gian) nhỏ nhất qua một tập các đỉnh trên đồ thị.
Một công ty giao hàng nhỏ có trụ sở tại Hà Nội, Việt Nam, cần phải giao hàng đến 5 địa điểm khác nhau trong thành phố Mục tiêu của họ là tối ưu hóa lộ trình để giảm thiểu tổng quãng đường di chuyển Chúng ta sẽ sử dụng bài toán người giao hàng dựa trên chu trình Hamilton để tìm ra lộ trình tối ưu.
Các địa điểm cụ thể là:
1 Trụ sở công ty (điểm xuất phát và kết thúc): 1 Lê Thánh Tông, Hoàn Kiếm
2 Điểm giao hàng A: 25 Láng Hạ, Ba Đình
3 Điểm giao hàng B: 132 Xuân Thủy, Cầu Giấy
4 Điểm giao hàng C: 56 Phạm Hùng, Nam Từ Liêm
5 Điểm giao hàng D: 100 Trần Duy Hưng, Cầu Giấy
6 Điểm giao hàng E: 75 Đường Thành, Hoàn Kiếm
Giả sử chúng ta có thông tin khoảng cách giữa các điểm như sau (đơn vị: km):
Bằng cách áp dụng chu trình Hamilton ta có thể tính ra được quãng đường ngắn nhất có thể đi:
Chu trình Hamilton: 0 5 4 3 2 1 0 với tổng đường đi: 30
Chu trình Hamilton: 0 1 2 3 4 5 0 với tổng đường đi: 30
Nên ta suy ra được khoảng cách ngắn nhất để qua tất cả các điểm và quay về là 30 km với 2 cách đi
Giải sử có một mạng máy tính nội bộ (của một cơ quan, tổ chức nào đó…) được bố trí như hình vẽ.
Khi đó, cần phải tính toán sao cho việc lắp đặt đường dây từ vị trí 1 để kết nối với các vị trí khác sao cho mỗi vị trí, đường dây đi qua đúng 1 lần và đảm bảo chi phí lắp đặt là ít nhất hoặc chiều dài dây cáp lắp đặt là ngắn nhất.
Qua hai ví dụ trên, ta có thể thấy những ứng dụng của Đồ thị Hamilton và bài toán Người giao là rất phong phú và phổ biến trong cuộc sống hàng ngày Chẳng hạn ví dụ của bài toán trên có thể mở rộng cho bất kỳ lĩnh vực khác như:
Xe cứu thương ở vị trí 1, bệnh nhân ở vị trí 3 Vậy phải tìm đường đi từ 1 đến 3 rồi trở về 1 như thế nào để đảm bảo thời gian đi là ít nhất.
Nhà máy nước của một thành phố đặt ở vị trí 1, các hộ gia đình ở các vị trí còn lại.Vậy phải lắp đặt hệ thống ống nước tới các hộ gia đình sao cho chi phí bỏ ra là thấp nhất.
Cài đặt chương trình và minh họa kết quả
Cấu trúc dữ liệu và giải thuật
def nhap(): global n, adj, used, HC, start_vertex #Tạo biến n = int(input("Nhập số đỉnh của đồ thị: ")) adj = [] print("Nhập ma trận kề có trọng số:") for _ in range(n): adj.append(list(map(int, input().split()))) #Nhập dữ liệu vào ma trận start_vertex = int(input("Nhập đỉnh xuất phát (đánh số từ 0 đến n-1): ")) #Chọn đỉnh xuất used = [False] * n #Khởi tạo danh sách, kiểm tra điểm nào đã được def hop_le(v, pos): #Kiểm tra đỉnh v có thể thêm vào Chu trình Hamilton tại vị trí pos hay if adj[HC[pos-1]][v] == 0: return False if v in HC[:pos]: return False return True def tong_trong_so(HC): return sum(adj[HC[i]][HC[i+1]] for i in range(len(HC)-1)) #Tính tổng trọng số của chu trình def chu_trinh_Hamilton(pos, chu_trinh_va_trong_so): if pos == n: if adj[HC[pos-1]][HC[0]] != 0:
HC.append(HC[0]) # Thêm đỉnh đầu vào cuối để tạo thành chu trình chu_trinh_va_trong_so.append((list(HC), tong_trong_so(HC)))
HC.pop() # Xóa đỉnh cuối để tiếp tục tìm chu trình khác return else: for v in range(n): if hop_le(v, pos):
HC[pos] = v chu_trinh_Hamilton(pos + 1, chu_trinh_va_trong_so)
HC[pos] = -1 def in_ket_qua(chu_trinh_va_trong_so): if not chu_trinh_va_trong_so: print("Không có chu trình Hamilton!") else: for chu_trinh, trong_so in chu_trinh_va_trong_so: print('Chu trình Hamilton: ', ' '.join(map(str, chu_trinh)), 'với tổng đường đi:', trong_so) if name == " main ": #Gọi lại các hàm đã được định nghĩa ở trên nhap()
HC[0] = start_vertex chu_trinh_va_trong_so = [] chu_trinh_Hamilton(1, chu_trinh_va_trong_so) in_ket_qua(chu_trinh_va_trong_so)
Cấu trúc dữ liệu
1 n: Biến toàn cục lưu trữ số lượng đỉnh trong đồ thị.
2 adj: Một danh sách các danh sách, đại diện cho ma trận kề có trọng số của đồ thị.
“adj[i][j]” chứa trọng số của cạnh nối từ đỉnh i đến đỉnh j Nếu không có cạnh nối, trọng số sẽ là 0.
3 start_vertex: biến lưu trưc đỉnh xuất phát của chu trình Hamilton.
4 used: danh sách các giá trị boolean, được sử dụng để theo dõi các đỉnh đã được truy cập trong quá trình tìm kiếm chu trình.
5 HC (Hamilton Cycle): một danh sách được sử dụng để lưu trữ chu trình Hamilton hiện tại đang được xây dựng Mỗi phần tử trong danh sách này đại diện cho một đỉnh trong chu trình.
6 chu_trinh_va_trong_so: một danh sách tuple chứ một chu trình Hamilton và tổng trọng số của chu trình đó Được sử dụng để lưu trữ tất cả các chu trình Hamilton hợp lệ và tổng trọng số tương ứng của chúng sau khi tìm kiếm.
Các hàm trong chương trình:
+nhap(): Hàm này đọc dữ liệu từ người dùng bao gồm số lượng đỉnh, ma trận kề và đỉnh xuất phát.
+hop_le(v, pos): kiểm tra xem việc thêm đỉnh v vào vị trí pos trong chu trình Hamilton có hợp lệ không.
+tong_trong_so(HC): tính tổng trọng số các cạnh trong chu trình Hamilton.
+chu_trinh_Hamilton(pos, chu_trinh_va_trong_so): tìm tất cả các chu trình Hamilton bắt đầu từ đỉnh đã chọn, sử dụng phương pháp quay lùi.
+in_ket_qua(chu_trinh_va_trong_so): in ra các chu trình và tổng trọng số của chúng
Giải thuật
Nhập số lượng đỉnh n của đồ thị.
Nhập ma trận kề adj, biểu diễn trọng số của các cạnh giữa các đỉnh.
Chọn một đỉnh xuất phát start_vertex.
Khởi tạo mảng HC (Hamilton Cycle) với tất cả các giá trị là -1 HC sẽ lưu trữ chu trình Hamilton đang được xây dựng.
Đặt HC[0] bằng start_vertex.
Khởi tạo danh sách chu_trinh_va_trong_so để lưu trữ các chu trình Hamilton và tổng trọng số của chúng.
Bước 3: Tìm kiếm Chu Trình Hamilton
Sử dụng hàm chu_trinh_Hamilton(pos, chu_trinh_va_trong_so) để tìm kiếm chu trình Hamilton.
Nếu pos bằng n, kiểm tra xem có thể trở về đỉnh xuất phát từ đỉnh cuối cùng hay không Nếu có, thêm chu trình này vào chu_trinh_va_trong_so.
Nếu pos nhỏ hơn n, lặp qua mọi đỉnh và kiểm tra xem nó có thể được thêm vào HC tại vị trí pos hay không bằng hàm hop_le(v, pos) Nếu có, gọi đệ quy chu_trinh_Hamilton với pos + 1/.
Bước 4: Kiểm Tra Điều Kiện Hợp Lệ
Hàm hop_le(v, pos) kiểm tra xem liệu có thể thêm đỉnh v vào chu trình tại vị trí pos hay không Điều kiện là phải cso cạnh từ đỉnh trước đó đến v và v không được xuất hiện trước đó trong chu trình.
Bước 5: Tính Tổng Trọng Số
Hàm tong_trong_so(HC) tính tổng trọng số của chu trình Hamilton bằng cách cộng trọng số của tất cả các cạnh trong chu trình.
Cuối cùng, hàm in_ket_qua(chu_trinh_va_trong_so) in ra tất cả các chu trìnhHamilton và tổng trọng số của chúng Nếu không tìm thấy chu trình nào,thông báo không có chu trình Hamilton.
Minh họa kết quả
Đồ thị G, minh họa các địa điểm trong thành phố và khoảng cách tương ứng giữa các địa điểm trong thành phố.
Nhập dữ liệu bài toán :
Từ đó đưa ra kết luận có 2 cách đi để tổng khoảng cách giữa các địa điểm là ngắn nhất:
- Từ trụ sở (đỉnh 0)→ điểm giao hàng A ( đỉnh 1)→ điểm giao hàng B ( đỉnh 2)
→ điểm giao hàng C ( đỉnh 3) → điểm giao hàng D ( đỉnh 4)→ điểm giao hàng
-Từ trụ sở (đỉnh 0)→ điểm giao hàng E (đỉnh 5)→ điểm giao hàng D ( đỉnh 4)→ điểm giao hàng C ( đỉnh 3) → điểm giao hàng B ( đỉnh 2) →điểm giao hàng A
Với tổng đường đi là 30 km
-Đồ án đã hoàn thành việc tìm được đường đi ngắn nhất qua các điểm cần giao hàng Với chương trình này chúng ta có thể tìm được đường đi ngắn nhất dựa trên chu trình Hamilton để tìm ra lộ trình tối ưu qua đó giảm thiểu lộ trình di chuyển
1 ANTON, H and C RORRES Elementary Linear Algebra: Applications Version, 7th ed New York: John Wiley & Sons, Inc, 1994
2 Nguyễn Cam, Chu Đức Khánh, Lý thuyết đồ thị, Nhà xuất bản trẻ 1998( chương 1-3)
3 Meyer C.D, Matrix analysis and Applied linear algebra, SIAM, 2000
4 KOLMAN, B, Introductory, Linear Algebra with Applications, New Jersey: PrenticeHall, Inc, 1997