Mục này trình bày tóm tắt năm thuật toán cận tỷ lệ tốt nhất hiện biết để tiến hành đánh giá thực nghiệm.
3.1.1.1 Thuật toán Blum et al.
Blum et al. [6] cho rằng chi phí tối ưu của bài toán k−MST (bài toán cây khung nhỏ nhất đi qua k đỉnh [15]) được xem như cận dưới của độ trễ đỉnh thứ k trong hành trình tối ưu MLP. Thuật toán Blum et al. được trình bày như sau: Giả sử, có tập lời giải Tk thu được từ thuật toán gần đúng cận tỷ lệ β cho bài toán k−MST với gốc v1 (k = 2, 3, …, n). Đối với mỗi số nguyên l (l = 2, 3, .., n), chọn cây Tl có chi phí lớn nhất trong khoảng (2l, 2l+1]. Sau đó, với mỗi cây Tl, nhân đôi mỗi cạnh của cây để thu được một chu trình Euler Cl (l = 2, 3, …, n) có gốc là v1. Kết nối các chu trình Cl, đồng thời loại bỏ các đỉnh đã được duyệt từ các chu trình
Thuật toán có cận tỷ lệ là 16 nếu sử dụng thuật toán gần đúng cận tỷ lệ 2 cho bài toán
k−MST [15]. Giải bài toán k−MST, chúng ta cần O(n(n+log cmax))×log n) để gọi PCST (Prize collection steiner tree) với cmax là chi phí cạnh lớn nhất và O(n2×log n) để thực thi PCST. Bởi vậy, độ phức tạp thời gian của thuật toán là O(n3(n+log cmax))×log2n).
3.1.1.2 Thuật toán Goeman et al.
Goemans et al. [18] cho rằng nếu có một thuật toán tìm hành trình ngắn nhất đi qua k đỉnh trong không gian metric với cận tỷ lệβ, thì tồn tại một thuật toán có cận tỷ lệ 359×β cho bài toán MLP. Với mỗi j = 1, 2, …, n, thuật toán tìm hành trình ngắn nhất Tj đi qua j đỉnh. Sau đó, ta kết nối các Tj để thu được hành trình MLP. Mục đích của việc kết nối là lựa chọn các chỉ số j1, …, jm sao cho khi kết nối các
1 j T , ..., m j T ta thu được hành trình có độ trễ là nhỏ nhất. Để kết nối các hành trình Tj (j = 2, 3, …, n), Goemans et al. đưa ra thuật toán như sau: Xây dựng đồ thị đầy đủ có hướng Gn với cung (i, j) đi từ min (i, j) đến max (i, j) và có độ dài là ( ( ))
2
j n i j d
(với dj là độ dài của Tj). Thuật toán sau đó tìm đường đi ngắn nhất từ đỉnh 1 đến đỉnh n. Giả sử, đường đi đó đi qua các đỉnh 1 = j1 < j2 < ... < jm =n, thì hành trình MLP cuối cùng thu được bằng việc kết nối T =
1 j T , ..., . m j T
Sử dụng thuật toán cận tỷ lệ β = 2 cho bài toán k–MST [15], ta thu được một thuật toán có cận tỷ lệ là 7.18 cho bài toán MLP. So với thuật toán của Blum et al., thì thuật toán Goeman et al. cho cận tỷ lệ tốt hơn. Tuy nhiên, vẫn cần O(n(n+logcmax)×log n) để gọi PCST để tạo ra các k–MST, bởi vậy, thuật toán không cải thiện được về thời gian chạy.
3.1.1.3 Thuật toán Archer et al.
Archer et al. [1] không sử dụng thuật toán k-MST trong [15], thay vì đó, Archer et al. đề xuất thuật toán tạo ra một tập các cây k–MST (k = 2, …, n) bằng việc sử dụng kỹ thuật nới lỏng lagrangian. Sau đó, các cây này được kết nối theo thuật toán Goeman et al. [18] để thu được hành trình MLP. Cận tỷ lệ của thuật toán được Archer et al. chứng minh là 7.18. Thuật toán không giảm cận tỷ lệ so với thuật toán của Goeman et al. Tuy nhiên, độ phức tạp thời gian lại được cải thiện rõ rệt. Nhờ giảm được số lần gọi PCST xuống còn O(n×log n), nên độ phức tạp thời gian của thuật toán là O(n3×log2n). Archer et al. cũng đưa ra thuật toán ngẫu nhiên chỉ sử dụng O(log2n) cho lời gọi PCST và một thuật toán với cận tỷ lệ là (7.18 + ε) khi chỉ sử dụng O((1/ε)log2n) cho lời gọi PCST. Chi tiết thuật toán của Archer et al. được trình bày trong Thuật toán 3.1.
Thuật toán 3.1. Thuật toán Archer et al.
Đầu vào: Kn, Cij và v1 lần lượt là đồ thị đầy đủ, ma trận chi phí và đỉnh xuất phát.
Đầu ra: T là hành trình MLP. 1. BEGIN
2. Thu được Tk (k = j1, j2, ..., jm (1 = j1 < j2 <....< jm = n)) từ Get_k_Tree (Kn, Cij, v1, k);
3. Chuyển cácTk thành các hành trình Euler Ck. 4. T= Kết nối Ck theo thuật toán Goemans et al. [18]; 5. return T;
6. END
Thuật toán 3.2. Get_k_Tree (Kn, Cij, v1, k)
Đầu vào: Kn, Cij, v1, k lần lượt là một đồ thị đầy đủ, ma trận chi phí, đỉnh xuất phát và số lượng đỉnh trong cây.
Đầu ra: bk, Tk là cận dưới và lời giải k-MST 1. BEGIN
2. λmin = 0; λmax = cmax; Tlo= Ø; blo = 0; 3. δ = 1 – 1/(4n – 1);
4. while (λmin≤ λmax) do
5. λmid= (λmin + λmax ) / 2;
6. (Thi, bhi)= PCST(Kn, Cij, λmid, v1); 7. if (hi == k) then 8. bk = bhi; Tk= Thi; 9. break; 10. else 11. if (hi < k) 12. λmin= λmid;
13. if (|λmid– λ| < ((1 – δ)×cmin)/(δ×n)) then
14. bk = Interpolate(k, |Tlo|, |Thi|, blo, bhi, δ);
15. break;
16. end if
17. else
18. λmax = λmid;
19. if (|λmid – λ| < ((1 – δ)cmin)/(δ×n) then
20. bk= Interpolate(k, |Tlo|, |Thi|, blo, bhi, δ); 21. break; 22. end if 23. end if 24. Tlo = Thi; blo= bhi; λ = λmid; 25. end while 26. returnbk, Tk; 27. END
Chú ý: Hàm Interpolate là hàm nội suy bk từ blo và bhi như sau:
k = αlo×|Tlo|×δ + αhi×|Thi|×δ.
αlo +αhi= 1.
Xây dựng tập các k–MST (k = 2, …, n) bằng việc sử dụng thuật toán gần đúng cho bài toán PCST giá trị phạt được thiết lập là λ [17]. Thuật toán trả về cây T và một cận dưới. Nếu λ
= 0, thì kết quả trả về là một cây chứa một đỉnh gốc. Tương tự, nếu λ = cmax, thì kết quả trả về là một cây với n đỉnh. Đối với mỗi k =1, 2, …, n, thực hiện tìm kiếm nhị phân cho giá trị λ để thu được một cây với chính xác k đỉnh. Nếu thành công, thì ta thu được k–tree (Tk) và giá trị cận dưới. Ngược lại, ta có hai cây Tlo, Thi và hai giá trị cận dưới blo và bhi với |Tlo| < k và |Thi| >
k cho hai giá trị λlo và λhi. Nếu hai giá trị của λlo và λhi đủ gần, thì ta nội suy bk của cây có k
đỉnh từ blo và bhi theo hàm Interpolate. Chi tiết được trình bày trong Thuật toán 3.2.
Để giảm số lần gọi PCST xuống còn O(n×log n) trong tìm kiếm nhị phân khi mà
cmax/cmin= poly(n) (cmax, cmin lần lượt là chi phí của cạnh lớn nhất và nhỏ nhất), ta xóa các đỉnh trong khoảng cách cmax/4n3 so với đỉnh gốc. Sau đó, áp dụng thuật toán Thuật toán 3.1
để thu được hành trình bộ phận MLP. Cuối cùng, ta bổ sung đỉnh đã bị xóa vào hành trình bộ phận này để thu được hành trình MLP.
3.1.1.4 Thuật toán Chauhuri et al.
Hiện tại, trong hướng tiếp cận gần đúng cận tỷ lệ, các công trình [1, 6, 18] chỉ ra rằng chi phí tối ưu của bài toán k–MST được xem như cận dưới cho độ trễ đỉnh thứ k trong hành trình tối ưu MLP. Có một ngoại lệ khi K.Chaudhuri et al. [9] chỉ ra rằng lời giải tối ưu của bài toán hành trình ngắn nhất đi qua k đỉnh (ta gọi là bài toán k–troll) là một cận dưới tốt hơn cho độ trễ đỉnh thứ k trong hành trình tối ưu MLP. Tuy nhiên, bài toán k–troll cũng khó tương tự như bài toán k–MST, bởi vậy họ sử dụng thuật toán tìm cây khung đi qua k đỉnh Tk có chi phí bị chặn bởi chi phí của hành trình ngắn nhất đi qua k đỉnh. Do đó, nếu vẫn sử dụng thuật toán kết nối của Goemans et al. [18] để kết nối các Tk (k = 2, …, n), thì ta không phải mất cận tỷ lệ 2 cho bài toán k–MST, bởi vậy thuật toán có cận tỷ lệ 3.59 cho bài toán MLP.
K.Chaudhuri et al. biến đổi thuật toán cho việc tìm k–MST có đỉnh gốc v1 và một đỉnh cuối vend với chi phí bị chặn bởi chi phí hành trình ngắn nhất đi từ v1 đến vend. Về cơ bản, ta vẫn sử dụng thuật toán tạo ra các k-MST và cần “đoán” đỉnh cuối vend. Ta có (n – 1) khả năng cho việc “đoán” đỉnh cuối vend trong mỗi lần tạo cây k–tree (Tk ). Bởi vậy, với mỗi giá trị k,ta có tập (n – 1) k-tree khác nhau và ta chọn k-tree có chi phí nhỏ nhất là lời giải của bài toán k-
troll. Độ phức tạp thời gian của thuật toán là O(n5×log2n). Tuy nhiên, K.Chaudhuri et al. cho rằng chỉ cần tạo ra các k–tree với O(log n) giá trị λ khác nhau. Do đó, độ phức tạp thời gian của thuật toán giảm xuống là O(n4×log2n).
Thuật toán 3.3. Thuật toán K.Chaudhuri et al.
Đầu vào: Kn, Cij, v1 lần lượt là một đồ thị đầy đủ, ma trận chi phí, đỉnh gốc.
Đầu ra: Hành trình MLP. 1. BEGIN
2. Thu được Tk (k = j1, j2, ..., jm (1 = j1 < j2 <....< jm = n)) từ
Get_best_k_troll (Kn, Cij, v1, k);
3. Chuyển cácTk thành các hành trình Euler Ck. 4. T= Kết nối Ck theo thuật toán Goemans et al. [18]; 5. ReturnT;
6. END
Thuật toán 3.4. Get_best_k_troll (Kn, Cij, v1, k)
Đầu vào: Kn, Cij, v1 lần lượt là một đồ thị đầy đủ, ma trận chi phí, đỉnh gốc và số lượng đỉnh trong cây.
Đầu ra: Tk là cây cần tìm. 1. BEGIN 2. sT = Ø; 3. bT = +∞; Tk-troll = Ø; 4. for (i = 1; i ≤ n – 1; i ++) do 5. vend = {vKn | v # v1 và v sT}; 6. sT = sT {vend};
7. Tk = Get_k_troll(Kn, Cij, v1, vend, k); 8. if (bT > c(Tk)) 9. Tk-troll = Tk; bT = c(Tk); 10. end if 11. end for 12. returnTk-troll; 13. END
Hàm Get_k_troll bao gồm các bước giống với hàm Get_k_tree trong Thuật toán 3.2. Tuy nhiên, hàm Get_k_troll gọi thủ tục PCST với đỉnh cuối vend. Mỗi đỉnh dự đoán vend tạo ra một Tk . Ta chọn Tk với chi phí nhỏ nhất bởi hàm Get_best_k_troll trong Thuật toán 3.4. Để kết nối các Tk này, ta sử dụng thuật toán kết nối của Goemans et al. [18]. Chi tiết thuật toán được trình bày trong Thuật toán 3.3.
3.1.1.5 Thuật toán Arora et al.
Arora et al. [3] cho rằng có thể phân rã hành trình MLP thành các đoạn sao cho bất kỳ sự thay đổi nào trong mỗi đoạn không ảnh hưởng nhiều đến tổng độ trễ của hành trình MLP. Sau đó, thay thế mỗi đoạn bởi hành trình người du lịch tối ưu (optimum traveling salesman tour). Gọi
hành trình người du lịch tối ưu để thu được hành trình MLP có độ trễ nhiều nhất là (1 +
ε)×OPT, với ε > 0.
Arora et al. đã sử dụng ý tưởng này để xây dựng lược đồ xấp xỉ giải bài toán MLP trong không gian euclidean. Thuật toán của Arora et al. bao gồm các bước: Ban đầu, n đỉnh của đồ thị được bao phủ bởi một ô vuông (boundingbox) như Hình 3.1. Ta đặt một lưới LxL
trên ô vuông đó và di chuyển các đỉnh trong ô vuông đến điểm lưới gần nhất. Theo Arora et al., bước này còn được gọi là bước làm tròn (well_rounded) và độ trễ hành trình tối ưu MLP sau bước làm tròn nhiều nhất bằng O(δ×OPT) (0 < δ < ε và OPT là độ trễ của hành trình tối ưu MLP trước khi làm tròn). Tiếp theo, thao tác đệ quy chia nhỏ lưới LxL thành các ô vuông (square) có kích thước nhỏ hơn. Ta dừng việc chia khi mà mỗi ô vuông chứa nhiều nhất một đỉnh của đồ thị ban đầu. Trong Hình 3.2, ta coi ô vuông ban đầu là ô vuông mức 0 và các ô vuông tại mỗi lần chia nhỏ sẽ ứng với ô vuông mức 1, 2, … Việc phân chia này tạo ra một cây (quadtree) có gốc là hình vuông mức 0 (boundingbox) và các con của cây tại mỗi mức cũng là các hình vuông được được tạo thành bởi quá trình chia nhỏ như Hình 3.2. Mỗi nút của cây có bốn con và cây có O(L2) nút và độ sâu là O(log L). Trên mỗi cạnh ô vuông, có một tập các điểm gọi là portal. Mỗi ô vuông có bốn portal ở bốn góc và
n log
portal cách đều nhau trên mỗi cạnh. Ta định nghĩa một hành trình–(m, k) ((m, k)–light tour) là một hành trình đi qua mỗi cạnh của mỗi ô vuông trong một quadtree nhiều nhất k lần và chỉ tại một trong m
portal của nó như Hình 3.3. Phương pháp quy hoạch động ở bước cuối cùng được thực hiện để tìm một hành trình–(c×log n/ε, f×log n/ε) (c, f là hằng số và ε > 0) đi qua n đỉnh. Để ghi nhận lời giải, ta xây dựng một bảng tra cứu (tableMatrix) cho mỗi ô vuông (square) theo chiến lược từ dưới lên (bottom up). Khi xét một ô vuông của quadtree, cần liệt kê tất cả các khả năng cho ra một crossing (Hình 3.4) và tìm trong bảng tra cứu những hành trình bộ phận (hành trình đi qua k đỉnh và k < n) nào có thể ghép nối với nó để tạo thành một hành trình mới. Kiểm tra xem hành trình mới này có là hành trình–(c×log n/ε, f×log n/ε). Nếu đúng thì cập nhập vào trong bảng tra cứu. Khi kết thúc thuật toán quy hoạch động, có nhiều hơn một hành trình đi qua n đỉnh được tạo thành. Hành trình với độ trễ là nhỏ nhất được chọn là lời giải bài toán. Theo Arora et al. thì độ trễ hành trình thu được nhiều nhất bằng (1 + ε)×OPT. Chi tiết thuật toán được trình bày từ Thuật toán 3.5 đến Thuật toán 3.9.
Hình 3. 1 Hình vuông (bounding box) bao phủ các đỉnh
Hình 3. 3 Tập các portal
Hình 3. 4 Minh họa crossing đi qua các portal
Thuật toán 3.5. Thuật toán Arora et al.
Đầu vào: Kn, Cij, f, c lần lượt là đồ thị đầy đủ, ma trận chi phí, và các hằng số.
Đầu ra: Hành trình MLP tốt nhất. 1. BEGIN
2. boundingBox = Well_rounded (Kn);
3. squareMatrix = Construct_Shifted_Quadtree (boundingBox); 4. tableMatrix = DynamicProgramming(squareMatrix, f, c); 5. return hành trình qua n đỉnh có độ trễ nhỏ nhất từ tableMatrix;
6. END
Thuật toán 3.6. well_rounded (Kn)
Đầu vào: Kn là đồ thị đầy đủ.
Đầu ra: boundingBox là hình vuông (LxL). 1. BEGIN
2. L = O(n);
3. Chia hình vuông thành các ô vuông cách đềug = ϴ(δ×L/n2) (0 < δ < ε); 4. Chuyển mỗi đỉnh của Knđến điểm lưới gần nhất;
5. Chia độ dài các cạnh trong Kncho g; 6. return boundingBox;
Thuật toán 3.7. Construct_Shifted_Quadtree (boundingBox)
Đầu vào: Một well-roundedboundingBox.
Đầu ra: squareMatrixlưu trữ một tập cácQuadtrees. 1. BEGIN
2. ChiaboundingBox cho đến tận khi mỗi hình vuông chứa nhiều nhất một đỉnh để tạo thành các quadtree;
3. Sinh hai số ngẫu nhiên a, b (0 a, b < L);
4. Dịch các quatree lần lượt theo tọa độ x và tọa độ y bởi đại lượng a và b; 5. returnquadtrees;
6. END
Thuật toán 3.8. CalculateMatrix (sq: square, f, c)
Đầu vào: sq, f, c lần lượt là hình vuông, các hằng số cho trước. 1. BEGIN
2. Portals = sq.getPortals();
3. Crossing = doCrosings(Portals, sq); 4. fori := 0 to Crosings.getSize() do
5. Tìm trong tableMatrix những hành trình bộ phận thỏa crossing hiện tại. 6. Kết nối chúng để tạo thành một hành trình bộ phận mới.
7. if (hành trình này là hành trình–(clogn/ε, flogn/ε)) 8. Lưu trữ vào trong tableMatrix;
9. end for
10. END
Thuật toán 3.9. DynamicProgramming (squareMatrix: q, f, c)
Đầu vào: squareMatrix là một tập các quadtree
Đầu ra: Biến ma trận toàn cục lưu trữ các hành trình (clog n/ε, flog n/ε). 1. BEGIN
2. leaves = q.leaves(); 3. squares = q.getSquares(); 4. fori := 0 to leaves.getSize() do
5. calculateMatrix(leaves[i], f, c); 6. end for
7. fori:= 0 to squares.getSize() do
8. calculateMatrix(squares[i], f, c); 9. end for
10. return tableMatrix; 11. END
3.1.2 Kết quả thực nghiệm
Để đánh giá hiệu quả của thuật toán, hai thực nghiệm được tiến hành. Dữ liệu trong thực nghiệm đầu tiên bao gồm các file dữ liệu nhỏ trong bộ dữ liệu ngẫu nhiên từ 1 đến 3 và bộ dữ
liệu thực 2. Thực nghiệm thứ hai được tiến hành với các file dữ liệu lớn trong bộ dữ liệu thực 1 và bộ dữ liệu ngẫu nhiên 3. Đối với các file dữ liệu nhỏ, lời giải tối ưu từ thuật toán đúng cho phép ta đánh giá chính xác hiệu quả của các thuật toán. Đối với các file dữ liệu lớn, khi mà lời giải tối ưu chưa được biết đến, hiệu quả của các thuật toán chỉ được đánh giá một cách tương đối.
Các thuật toán được sử dụng trong các thực nghiệm gồm thuật toán của Blum et al. (BA), Goemans et al. (GKA), Archer et al. (AA), Chauhuri et al. (KA) và Arora et al. (AK). Đối với thuật toán của Arora et al., chúng tôi thực thi thuật toán cận tỷ lệ (1 + ε) với ε > 0 cho các file dữ liệu thỏa không gian euclidean và thuật toán cận tỷ lệ 11.65 cho các file dữ liệu phi euclidean. Ta ký hiệu: LB, L và T lần lượt là cận dưới, độ trễ lời giải và thời gian chạy chạy tính bằng phút của các thuật toán. Trong các bảng, các giá trị của các cột là kết quả của các thuật toán gần đúng bao gồm cận tỷ lệ p, LB và T. Trong các bảng từ 3.1 đến 3.2, cận tỷ lệ p L OPT / (OPT là lời giải tối ưu có được từ thuật toán đúng trong chương 2). Trong các bảng 3.3 và 3.4, do chưa biết lời giải tối ưu của các file dữ liệu lớn nên chúng ta sử dụng cận tỷ lệ như sau L fA(fA là cận dưới của giá trị tối ưu được lấy từ Archer et al. [1]) và cũng