BỘ CƠNG THƯƠNG
TRƯỜNG ĐẠI HỌC CƠNG THƯƠNG TP.HỒ CHÍ MINH
KHOA CƠNG NGHỆ THƠNG TIN
o0o
TIỂU LUẬN HỌC PHẦN: TRÍ TUỆ NHÂN TẠO
THUẬT TOÁN A* ỨNG DỤNG TRONG BÀI TOÁN GHÉP TRANH
Thành phố Hồ Chí Minh, tháng 12 năm 2023
BỘ CƠNG THƯƠNG
TRƯỜNG ĐẠI HỌC CƠNG THƯƠNG TP.HỒ CHÍ MINH
KHOA CƠNG NGHỆ THƠNG TIN
o0o
THUẬT TỐN A* ỨNG DỤNG TRONG BÀI TỐN GHÉP TRANH
Giảng viên hướng dẫn: Ngơ Thanh Hùng
Thành viên:
1. Lê Minh Tuyết Kỳ - 2001215901
2. Nguyễn Phương Loan - 2001215917
Thành phố Hồ Chí Minh, tháng 12 năm 2023
BẢNG PHÂN CƠNG
Họ tên
Cơng việc
Hồn thành
Tìm hiểu về code ứng dụng
Lê Minh Tuyết Kỳ
ghép tranh, soạn word
100%
Tìm hiểu về code ứng dụng
Nguyễn Phương Loan
ghép tranh, soạn powepotn
100%
LỜI MỞ ĐẦU
Trong ngành khoa học máy tính, một giải thuật tìm kiếm là một thuật tốn lấy đầu
vào là một bài toán và trả về kết quả là một lời giải cho bài tốn đó, thường là sau
khi cân nhắc giữa một loạt các lời giải có thể. Tập hợp tất cả các lời giải có thể cho
bài tốn được gọi là khơng gian tìm kiếm. Có những thuật tốn tìm kiếm “sơ đẳng”
khơng có thơng tin, đây là những phương pháp đơn giản và trực quan, trong khi đó
các thuật tốn tìm kiếm có thơng tin sử dụng hàm đánh giá heuristic giúp ta giảm
đáng kể thời gian cần thiết cho việc tìm kiếm lời giải. Để áp dụng được các giải
thuật tìm kiếm, ta cần chuyển khơng gian tìm kiếm về dạng đồ thị. Với dạng đồ thị
ta sẽ nắm bắt những mối liên hệ, những ảnh hưởng giữa các trạng thái của bài toán
một cách nhanh chóng và ngắn gọn. Trong phạm vi bài báo cáo, chúng em xin
trình bày ba thuật tìm kiếm tốn cơ bản và tiêu biểu với lý thuyết đồ thị đó là: Tìm
kiếm theo chiều rộng, Tìm kiếm theo chiều sâu và Tìm kiếm A*. Qua đó, chúng
em sẽ áp dụng giải thuật tìm kiếm A* để giải bài tốn 8 puzzle, một bài tốn quen
thuộc với những người lập trình, chúng em sẽ đưa ra cơ chế của thuật toán, ưu
nhược điểm cũng như độ phức tạp của những thuật toán trên.
MỤC LỤC
LỜI MỞ ĐẦU..................................................................................................................................1
NỘI DUNG......................................................................................................................................3
CHƯƠNG 1 GIỚI THIỆU MÔ TẢ BÀI TOÁN THỰC TẾ ĐƯỢC GIẢI QUYẾT......................3
1.1 Lý do chọn đề tài....................................................................................................................3
1.2 Mơ tả bài tốn ghép tranh......................................................................................................3
CHƯƠNG 2 THUẬT TOÁN A* ĐỂ GIẢI QUYẾT BÀI TOÁN..................................................5
2.1 Giới thiệu thuật tốn...............................................................................................................5
2.2 Mơ tả thuật tốn.....................................................................................................................5
2.3 Cài đặt thuật tốn...................................................................................................................6
2.4 Nhận xét.................................................................................................................................7
2.5 Độ phức tạp............................................................................................................................7
CHƯƠNG 3 CÁC CHỨC NĂNG CHÍNH VÀ HƯỚNG PHÁT TRIỂN.......................................8
3.1 Tổng quan về chức năng giao diện........................................................................................8
3.1.1 Chức năng bắt đầu sắp xếp..............................................................................................9
3.1.2 Chức năng tạm dừng sắp xếp........................................................................................10
3.1.3 Chức năng radom hình ảnh............................................................................................11
3.1.4 Chức năng thay đổi vị trí số của hình ảnh.....................................................................12
3.2 Hướng phát triển..................................................................................................................13
KẾT LUẬN...................................................................................................................................14
TÀI LIỆU THAM KHẢO.............................................................................................................15
NỘI DUNG
CHƯƠNG 1 GIỚI THIỆU MƠ TẢ BÀI TỐN THỰC TẾ ĐƯỢC GIẢI QUYẾT
1.1 Lý do chọn đề tài
Tính cấp thiết: Bài toán ghép tranh là một bài toán cổ điển trong lĩnh vực trí tuệ
nhân tạo. Bài tốn này có nhiều ứng dụng thực tế trong cuộc sống, chẳng hạn như trò
chơi ghép tranh, giải quyết các vấn đề xếp lịch, phân phối tài ngun,...
Tính khả thi: Thuật tốn A* là một thuật tốn tìm kiếm tối ưu được sử dụng rộng rãi
trong nhiều ứng dụng thực tế. Thuật tốn này có thể giải quyết bài tốn ghép tranh một
cách hiệu quả và chính xác.
Tính mới mẻ: Mặc dù thuật toán A* đã được nghiên cứu và ứng dụng rộng rãi,
nhưng việc ứng dụng thuật toán A* trong bài tốn ghép tranh vẫn cịn là một vấn đề mới
mẻ. Việc nghiên cứu đề tài này có thể góp phần nâng cao hiệu quả và độ chính xác của
việc giải quyết bài tốn ghép tranh.
1.2 Mơ tả bài tốn ghép tranh
Game ghép tranh(N-Puzzle) là một trò chơi khá hay và trí tuệ, nó được biết đến với
nhiều phiên bản và tên gọi khác nhau như: 8-puzzle, 15-puzzle, Gem puzzle, Boss puzzle.
Bài tốn N-puzzle là vấn đề cổ điển cho mơ hình thuật tốn liên quan đến trí tuệ nhân tạo.
Bài tốn đặt ra là phải tìm đường đi từ trạng thái hiện tại tới trạng thái đích. Và cho tới
nay vẫn chưa có thuật tốn tối ưu để giải bài tốn này.
Phần mềm N-Puzzle là một chương trình xây dựng trị chơi và giải quyết bài tốn
này. Phần mềm được viết trên nền Python, sử dụng giao diện đồ họa để mơ phỏng trị
chơi và thuật tốn A* để tìm đường đi. Người dùng có thể sử dụng chuột/bàn phím chơi
với các kích thước khác nhau và với hình ảnh khác nhau hoặc có thể sử dụng chức năng
tìm lời giải nhờ thuật tốn A*.
u cầu xây dựng bảng ơ vuông n hàng, n cột. Bảng gồm 1 ô trống và n-1 ô chứa
các số trong phạm vi [1, n-1]. Xuất phát từ một cách xếp bất kì, di chuyển ô trống lên
trên, xuống dưới, sang phải, sang trái để đưa các ơ về trạng thái đích. Sử dụng chuột hay
phím chức năng để di chuyển ơ trống. Chương trình có chức năng tự động chơi ở bất kì
trạng thái nào đó. Mỗi trạng thái của bảng số là một hốn vị của n phần tử. Ở đây ta có
thể mở rộng bằng việc thêm hình ảnh vào game hoặc gắn số vào hình ảnh để gợi ý cho
người chơi. Ở trạng thái ban đầu, các ô được sắp xếp ngẫu nhiên, và nhiệm vụ của người
chơi là tìm được cách đưa chúng về trạng thái đích(ơ đầu trống, các ô khác theo thứ tự
tăng dần từ trái qua phải, từ trên xuống dưới). Để đơn giản trong cách tiếp cận bài tốn, ta
giả định chỉ các ơ trống di chuyển trong bảng là di chuyển đến các vị trí khác nhau. Như
vậy tại một trạng thái bất kì có tối đa 4 cách di chuyển đến trạng thái khác(trái, phải, lên,
xuống).
Hình ảnh trạng thái đầu và trạng thái đích
Bước di chuyển của ô trống:
Hình ảnh bước di chuyển của ơ trống
CHƯƠNG 2 THUẬT TOÁN A* ĐỂ GIẢI QUYẾT BÀI TOÁN
2.1 Giới thiệu thuật tốn
Thuật tốn A* được mơ tả lần đầu tiên năm 1986 bởi Peter Hart, Nils Nilson
và Bertram Raphael. Trong báo cáo của họ, thuật tóa được gọi là thuật toán A, khi
sử dụng thuật toán này với một hàm đánh giá heuristic thích hợp sẽ thu được hoạt
động tối ưu, do đó mà có tên là A*.
Trong khoa học máy tính, A* là một thuật tốn tìm kiếm trong đồ thị. Thuật
tốn này tìm một đường đi từ nút khởi đầu tới một nút đích cho trước( hoặc tới
một nút thỏa mãn điều kiện đích). Thuật tốn này sử dụng một đánh giá heuristic
để xếp loại từng nút theo ước lượng về tuyến đường tốt nhất đi qua nút đó. Thuật
tốn này duyệt các nút theo thứ tự của đánh giá heuristic này. Do đó, thuật tốn A*
là một ví dụ của tìm kiếm theo lựa chọn tốt nhất(best-first search).
Xét bài tốn tìm đường – bài tốn mà A* thường được dùng để giải. A* xây
dựng tăng dần tất cả các tuyến đường từ điểm xuất phát cho tới khi nó tìm thấy
một đường đi chạm tới đích. Tuy nhiên, cũng như tất cả các thuật tốn tìm kiếm có
thơng tin nó chỉ xây dựng các tuyến đường có vẻ dần về đích.
Để biết những tuyến đường nào có khả năng sẽ dẫn tới đích, A* sử dụng một
hàm đánh giá heuristic về khoảng cách từ điểm bất kỳ cho tới đích. Trong trường
hợp tìm đường đi, đánh giá này có thể là khoảng cách đường chim bay - một đánh
giá xấy xỉ thường dùng cho khoảng cách của đường giao thông.
Điểm khác biệt của A* đối với tìm kiếm theo lựa chọn tốt nhất là nó cịn tính
đến khoảng cách đã đi qua. Điều đó làm cho A* đầy đủ và tối ưu, nghĩa là A* sẽ
ln tìm thấy đường đi ngắn nhất nếu tồn tại một đường đi như thế. A* không đảm
bảo sẽ chạy nhanh hơn các thuật tốn tìm kiếm đơn giản hơn. Trong một môi
trường dạng mê cung, cách duy nhất để đến đích có thể là trước hết phải đi về phía
xa đích và cuối cùng mới quay trở lại. Trong trường hợp đó, việc thử các nút theo
thứ tự “gần đích hơn thì được thử trước” có thể gây tốn thời gian.
2.2 Mơ tả thuật tốn
Giả sử n là một trạng thái đạt tới(có đường đi từ trạng thái ban đầu 𝑛0 tới 𝑛).
Ta xác định hàm đánh giá: 𝑓(𝑛) = 𝑔(𝑛) + ℎ(𝑛)
g(n) là chi phí từ nút gốc 𝑛0 tới nút hiện tại n
h(n) chi phí ước lượng từ nút hiện tại n tới đích
f(n) chi phí tổng thể ước lượng của đường đi qua nút hiện tại n đến
đích Một ước lượng heuristic h(n) được xem là chấp nhận được nếu với mọi
nút n
0 ≤ ℎ(𝑛) ≤ ℎ ∗ (𝑛)
Trong đó h*(n) là chi phí thật để đi từ nút n đến đích.
2.3 Cài đặt thuật toán
OPEN(FRINGE): tập chứa các trạng thái đã được sinh ra nhưng chưa được
xét đến. OPEN là một hàng đợi ưu tiên mà trong đó phần tử có độ ưu tiên cao nhất
là phần tử tốt nhất.
CLOSE: tập chứa các trạng thái đã được xét đến. Chúng ta cần lưu trữ những
trạng thái này trong bộ nhớ để phịng trường hợp khi có một trạng thái mới được
tạo ra lại trùng với một trạng thái mà ta đã xét đến trước đó.
Khi xét đến một trạng thái 𝑛𝑖 trong OPEN bên cạnh việc lưu trữ 3 giá trị cơ
bản g, h, f để phản ánh độ tốt của trạng thái đó, A* cịn lưu trữ thêm hai thông số
sau:
Trạng thái cha của trạng thái 𝑛𝑖; (ký hiệu Cha(𝑛𝑖)): cho biết trạng thái dẫn
đến trạng thái 𝑛𝑖.
Danh sách các trạng thái tiếp theo của 𝑛𝑖: danh sách này lưu trữ các trạng thái
kế tiếp 𝑛𝑘 của nị sao cho chi phí đến 𝑛𝑘 thơng qua 𝑛𝑖; từ trạng thái ban đầu là
thấp nhất. Thực chất danh sách này có thể được tính từ thuộc tính Cha của
các trạng thái đã được lưu trữ. Tuy nhiên việc tính tốn này có thể mất nhiều
thời gian(khi tập OPEN,CLOSE được mở rộng) nên người ta thường lưu trữ
ra một danh sách riêng.
Thuật toán A*
Function Astar(𝑛0,𝑛𝑔𝑜𝑎𝑙)
3.1. Đặt OPEN chỉ chứa 𝑛0. Đặt g(𝑛0) = h(𝑛0) = f(𝑛0) = 0. Đặt CLOSE là tập rỗng
3.2. Lặp lại các bước sau cho đến khi gặp điều kiện dừng
3.2.a Nếu OPEN rỗng: bài tốn vơ nghiệm, thốt.
3.2.b Ngược lại, chọn 𝑛𝑖 trong OPEN sao cho f(𝑛𝑖 ) sao cho f(𝑛𝑖) nhỏ nhất
3.2.b.1 Lấy 𝑛𝑖 ra khỏi OPEN và đưa 𝑛𝑖vào CLOSE
3.2.b.2
Nếu 𝑛𝑖 chính là đích 𝑛𝑔𝑜𝑎𝑙 thì thốt và thơng báo lời giải là 𝑛𝑖
3.2.b.3 Nếu 𝑛𝑖, khơng phải là đích. Tạo danh sách tất cả các trạng thái kế tiếp
của 𝑛𝑖 . Gọi một trạng thái này là 𝑛𝑘. Với mỗi 𝑛𝑘, làm các bước sau:
3.2.b.3.1 Tính g(𝑛𝑘) = g(𝑛𝑖) + cost(𝑛𝑖, 𝑛𝑘); h(𝑛𝑘);
f(𝑛𝑘) = g(𝑛𝑘) + h(𝑛𝑘).
3.2.b.3.2 Đặt Cha(𝑛𝑘) = 𝑛𝑖
3.2.b.3.3 Nếu 𝑛𝑘 chưa xuất hiện trong OPEN và CLOSE thì thêm 𝑛𝑘 vào
OPEN
Nhận xét
Thuật tốn A* có tính “đầy đủ” theo – có nghĩa nó sẽ ln tìm thấy lời giải nếu bài
tốn đó có lời giải. Bên cạnh đó A* cịn “tối ưu”. Muốn A* tối ưu thì hàm h(n) phải có
tính chấp nhận được – tức là nó khơng bao giờ đánh giá cao hơn chi phí nhỏ nhất thực sự
của việc đi tới đích (trong trường hợp tập đóng). Nếu khơng dùng tập đóng, thì h(n) phải
có tính đơn điệu (hay nhất qt qn) – tức là nó khơng bao giờ đánh giá chi phí đi từ
một nút tới một nút kề nó cao hơn chi phí thực. Một cách hình thức, nếu m là nút kế tiếp
của n thì:
ℎ(𝑛) ≤ 𝑔(𝑚) – 𝑔(𝑛) + ℎ(𝑚)
Thuật tốn A* cịn có tính chất hiệu quả một cách tối ưu với mọi hàm heuristic h, có
nghĩa là khơng có thuật tốn nào cũng sử dụng hàm heuristic đó mà chỉ phải mở rộng ít
nút hơn A*, trừ khi có một số lời giải chưa đầy đủ mà tại đó ℎ h dự đốn chính xác chi
phí của đường đi tối ưu.
2.4 Độ phức tạp
Độ phức tạp của A* phụ thuộc vào hàm đánh giá h(n). Độ phức tạp đó sẽ là
hàm đa thức nếu h(n) thỏa mãn điều kiện sau:
|ℎ(𝑛) – ℎ ∗ (𝑛)| 𝑂(𝑙𝑜𝑔 ℎ ∗ (𝑛))
Với h*(n) là hàm cho kết quả là chi phí chính xác để đi từ nút đang xét n tới
đích.Cụ thể, sai số của h(n) không nên tăng nhanh hơn log h*(n). Trong trường
hợp xấu nhất, độ phức tạp sẽ lên đến hàm mũ, vấn đề sử dụng bộ nhớ của A* khá
rắc rối, nó phải ghi nhớ số lượng nút tăng theo hàm mũ. Một số biến thể của A*
được phát triển để giải quyết vấn đề này.
CHƯƠNG 3 CÁC CHỨC NĂNG CHÍNH VÀ HƯỚNG PHÁT TRIỂN
3.1 Tổng quan về chức năng giao diện
3.1.1 Chức năng bắt đầu sắp xếp
Chức năng bắt đầu sắp xếp trong trị chơi ghép hình Side Puzzle là chức năng cho phép
người chơi bắt đầu giải một câu đố mới. Để sử dụng chức năng này, người chơi cần nhấn
nút “Bat Dau”. Khi nhấn nút này, câu đố sẽ được xáo trộn ngẫu nhiên và người chơi sẽ
bắt đầu giải câu đố từ đầu.
Trên hình, chúng ta có thể thấy rằng câu đố hiện tại có các ơ được đánh số từ 1 đến
8. Các ô này được sắp xếp theo thứ tự ngẫu nhiên. Để giải câu đố, người chơi cần sắp xếp
các ô sao cho chúng hiển thị các số từ 1 đến 8 theo thứ tự tăng dần, từ trái sang phải.
Chức năng bắt đầu sắp xếp là một chức năng quan trọng trong trò chơi ghép hình
Side Puzzle. Nó cho phép người chơi bắt đầu giải một câu đố mới bất cứ lúc nào. Chức
năng này cũng giúp người chơi làm mới trí nhớ và tiếp tục thử thách bản thân.
3.1.2 Chức năng tạm dừng sắp xếp
Chức năng dừng sắp xếp cho phép người chơi tạm dừng trò chơi trong khi họ đang
giải câu đố. Để sử dụng chức năng này, người chơi cần nhấn nút “Dung”. Khi nhấn nút
này, trị chơi sẽ tạm dừng và người chơi sẽ có thể tiếp tục giải câu đố sau đó.
Chức năng Dừng sắp xếp là một chức năng hữu ích trong trị chơi ghép hình Side
Puzzle. Nó cho phép người chơi tạm dừng trò chơi bất cứ lúc nào, chẳng hạn như khi họ
cần nghỉ ngơi hoặc khi họ cần giải quyết một vấn đề khác. Chức năng này cũng giúp
người chơi tránh bị mất tiến độ nếu họ phải dừng trò chơi đột ngột.
3.1.3 Chức năng radom hình ảnh
Chức năng Random Image trong trò chơi Slide Puzzle cho phép người chơi tạo ra
các câu đố mới và thú vị bằng cách sử dụng các hình ảnh ngẫu nhiên. Để sử dụng chức
năng này, người chơi cần nhấp vào nút "Random". Sau đó, một hình ảnh mới sẽ được
hiển thị trên bàn cờ. Người chơi có thể tiếp tục sử dụng các phím mũi tên để di chuyển
các ô số và cố gắng sắp xếp chúng thành hình ảnh hồn chỉnh.
Chức năng Random Image có thể giúp người chơi giải trí và thư giãn. Nó cũng có
thể được sử dụng để tạo ra các thách thức mới và thú vị.
Dưới đây là một số ví dụ về cách sử dụng chức năng Random Image:
Người chơi có thể sử dụng chức năng Random Image để tạo ra các câu đố ngẫu
nhiên.
Người chơi có thể sử dụng chức năng Random Image để tạo ra các câu đố theo
chủ đề. Ví dụ, họ có thể đặt mục tiêu giải quyết một câu đố với hình ảnh của động
vật, hoa hoặc phong cảnh.
3.1.4 Chức năng thay đổi vị trí số của hình ảnh
Chức năng "Thay đổi vị trí số của hình ảnh" trong trị chơi xếp hình Slide Puzzle là chức
năng cho phép người chơi thay đổi vị trí của các số trên hình ảnh. Chức năng này có thể
được sử dụng để tạo ra các bố cục ngẫu nhiên mới hoặc để tạo ra các bố cục phù hợp với
sở thích của người chơi.
Chức năng này có thể được truy cập bằng cách nhấn vào nút "Thay doi vi tri so" ở
phía dưới màn hình. Khi nút được nhấn, một menu sẽ xuất hiện cho phép người chơi
chọn số mà họ muốn di chuyển. Người chơi có thể di chuyển các số theo bất kỳ hướng
nào bằng cách sử dụng các phím mũi tên trên bàn phím hoặc bằng cách vuốt trên màn
hình.
Chức năng "Thay đổi vị trí số của hình ảnh" là một chức năng bổ sung thú vị trong
trò chơi xếp hình Slide Puzzle. Chức năng này cho phép người chơi có nhiều cách hơn để
chơi trị chơi và tạo ra các bố cục mới và thú vị.
3.2 Hướng phát triển
- Cài đặt thêm chức năng chọn nhiều ô hơn: Chức năng này sẽ giúp người chơi có thể thử
thách bản thân với các ơ chơi lớn hơn. Khi kích thước ơ chơi lớn hơn, độ khó của trị chơi
sẽ tăng lên. Người chơi cần có khả năng tư duy logic và tính tốn tốt hơn để có thể hồn
thành trị chơi.
Ví dụ: như 16 ơ, 25 ô…
- Kết hợp thêm thuật toán Best First Search hay Breadth First Search: Kết hợp thêm thuật
tốn tìm kiếm sẽ giúp trò chơi trở nên thú vị và hấp dẫn hơn. Khi sử dụng thuật tốn tìm
kiếm, máy tính sẽ tự động tìm ra đường đi ngắn nhất từ trạng thái ban đầu đến trạng thái
đích. Người chơi có thể theo dõi q trình tìm kiếm của máy tính và học hỏi thêm về
thuật tốn tìm kiếm.
- Cài đặt thêm chức năng đếm số bước đi: Chức năng này sẽ giúp người chơi theo dõi
được tiến độ của mình trong q trình chơi. Người chơi có thể cố gắng giảm số bước di
chuyển của mình để đạt được thành tích cao hơn.
- Cài đặt thêm chức năng chọn hình ảnh để cho cho người chơi có thể chọn hình ảnh u
thích của mình vì nó cho phép người chơi chọn hình ảnh u thích cũng có thể giúp tăng
tính sáng tạo của trị chơi. Người chơi có thể sử dụng trí tưởng tượng của mình để tạo ra
các bố cục mới và thú vị cho hình ảnh của mình.
KẾT LUẬN
Thơng qua việc tìm hiểu và nghiên cứu đề tài này, chúng em đã có được
những kiến thức bổ ích về ứng dụng trí tuệ nhân tạo vào giải quyết vấn đề thực
tế. Cụ thể, chúng em đã được làm quen với bài toán ghép tranh (8-puzzle), một
bài toán cổ điển trong trí tuệ nhân tạo. Chúng em đã tìm hiểu các phương pháp
giải bài tốn này, bao gồm tìm kiếm theo chiều rộng, tìm kiếm theo chiều sâu và
tìm kiếm A*.
Chúng em nhận thấy rằng mỗi phương pháp đều có ưu và nhược điểm
riêng. Tìm kiếm theo chiều rộng có độ phức tạp thời gian thấp, nhưng có thể dẫn
đến bộ nhớ cạn kiệt. Tìm kiếm theo chiều sâu có thể tìm ra giải pháp trong mọi
trường hợp, nhưng có độ phức tạp thời gian cao. Tìm kiếm A* là phương pháp
hiệu quả nhất, có độ phức tạp thời gian trung bình giữa tìm kiếm theo chiều rộng
và tìm kiếm theo chiều sâu.
Chúng em hy vọng rằng những nghiên cứu đánh giá của chúng em sẽ góp
phần bổ sung thêm một hướng giải quyết cho bài toán ghép tranh (8-puzzle). Do
thời gian có hạn nên đề tài khơng tránh khỏi những sai sót, mong thầy cơ góp ý,
đánh giá giúp chúng em có thêm được những kinh nghiệm quý báu.