Các thuật toán tìm đường hiện đại để thay đổi biểu đồ (D *, D * -Lite, LPA *, v.v.) khác nhau như thế nào?


96

Rất nhiều thuật toán tìm đường đã được phát triển trong những năm gần đây có thể tính toán đường đi tốt nhất để phản ứng với biểu đồ thay đổi nhanh hơn nhiều so với A * - chúng là gì và chúng khác nhau như thế nào? Là họ cho các tình huống khác nhau, hoặc làm một số người khác lỗi thời?


Đây là những cái tôi đã có thể tìm thấy cho đến nay:

Tôi không chắc những điều này áp dụng cho vấn đề cụ thể của mình - tôi sẽ đọc tất cả nếu cần, nhưng nó sẽ giúp tôi tiết kiệm rất nhiều thời gian nếu ai đó có thể viết tóm tắt.


Vấn đề cụ thể của tôi: Tôi có một lưới với một khởi đầu, một kết thúc và một số bức tường. Tôi hiện đang sử dụng A * để tìm đường dẫn tốt nhất từ ​​đầu đến cuối.

Hình ảnh 2

Người dùng sau đó sẽ di chuyển một bức tường và tôi phải tính toán lại toàn bộ đường dẫn một lần nữa. Bước "tường di chuyển / tính toán lại đường dẫn" xảy ra nhiều lần liên tiếp, vì vậy tôi đang tìm kiếm một thuật toán có thể nhanh chóng tính toán lại đường dẫn tốt nhất mà không phải chạy lặp lại đầy đủ A *.

Mặc dù, tôi không nhất thiết phải tìm kiếm một sự thay đổi thành A * - nó có thể là một thuật toán hoàn toàn riêng biệt.


3
Bạn đã xem D * chưa? Đó là một thuật toán gia tăng và nếu tôi nhớ chính xác, nên xử lý một tình huống chính xác như thế này. Tôi đã từng thấy một con robot sử dụng nó để tìm đường trong đó có những người đi bộ ngẫu nhiên trong môi trường.
Juho

7
@Kaveh: Tại sao không yêu cầu tổng quan về công nghệ tiên tiến trong thuật toán tìm đường động "cấp độ nghiên cứu?" Field-D * chưa đầy 5 tuổi và TÌM KIẾM ít hơn 3 ..
BlueRaja - Danny Pflughoeft

7
Tôi không chắc tại sao đây không phải là một câu hỏi thích hợp cho diễn đàn này. đây không phải là một chủ đề đã ổn định và cũ
Suresh Venkat

5
@ BlueRaja-DannyPflughoeft Tôi cũng nghĩ rằng đây là một câu hỏi hay, ở cấp độ nghiên cứu. Tôi sẽ thêm một câu trả lời dựa trên nhận xét của tôi và mở rộng nó một chút.
Juho

4
@ BlueRaja-DannyPflughoeft Đã liên kết trên reddit.
U2EF1

Câu trả lời:


77

Vì vậy, tôi lướt qua các giấy tờ, và đây là những gì tôi lấp lánh. Nếu có ai hiểu biết nhiều hơn về vấn đề này, xin vui lòng sửa cho tôi nếu tôi sai (hoặc thêm câu trả lời của riêng bạn và tôi sẽ chấp nhận thay vào đó!) .

Liên kết đến mỗi bài báo có thể được tìm thấy trong câu hỏi, ở trên.

  • Tính toán lại đơn giản
    • D * (còn gọi là Dynamic A * ) (1994): Trong lần chạy đầu tiên, D * chạy rất giống với A *, tìm ra con đường tốt nhất từ ​​đầu đến cuối rất nhanh. Tuy nhiên, khi đơn vị di chuyển từ đầu đến cuối, nếu biểu đồ thay đổi, D * có thể nhanh chóng tính toán lại đường đi tốt nhất từ ​​vị trí của đơn vị đó đến kết thúc, nhanh hơn nhiều so với việc chạy lại A * từ vị trí của đơn vị đó. D *, tuy nhiên, có tiếng là cực kỳ phức tạp và đã hoàn toàn bị lỗi thời bởi D * -Lite đơn giản hơn nhiều.
    • Tập trung D * (1995): Một cải tiến cho D * để làm cho nó nhanh hơn / "thời gian thực hơn". Tôi không thể tìm thấy bất kỳ sự so sánh nào với D * -Lite, nhưng cho rằng điều này cũ hơn và D * -Lite được nói nhiều hơn, tôi cho rằng D * -Lite bằng cách nào đó tốt hơn.
    • DynamicSWSF-FP (1996): Lưu trữ khoảng cách từ mọi nút đến nút kết thúc. Có một thiết lập ban đầu lớn để tính toán tất cả các khoảng cách. Sau khi thay đổi biểu đồ, nó chỉ có thể cập nhật các nút có khoảng cách đã thay đổi. Không liên quan đến cả A * và D *. Hữu ích khi bạn muốn tìm khoảng cách từ nhiều nút đến kết thúc sau mỗi thay đổi; mặt khác, LPA * hoặc D * -Lite thường hữu ích hơn.
    • LPA * / Incremental A * (2001): LPA * (Kế hoạch trọn đời A *) , còn được gọi là Incremental A * (và đôi khi, khó hiểu là "LPA", mặc dù nó không liên quan đến thuật toán khác có tên LPA) là một kết hợp giữa DynamicSWSF-FP và A *. Trong lần chạy đầu tiên, nó hoàn toàn giống với A *. Tuy nhiên, sau những thay đổi nhỏ đối với biểu đồ, các tìm kiếm tiếp theo từ cùng một cặp bắt đầu / kết thúc có thể sử dụng thông tin từ các lần chạy trước để giảm đáng kể số lượng nút cần kiểm tra, so với A *. Đây chính xác là vấn đề của tôi, vì vậy có vẻ như LPA * sẽ phù hợp nhất với tôi. LPA * khác với D * ở chỗ nó luôn tìm thấy con đường tốt nhất từ ​​cùng một khởi đầu đến cùng một kết thúc; nó không được sử dụng khi điểm bắt đầu di chuyển(chẳng hạn như các đơn vị di chuyển dọc theo con đường tốt nhất ban đầu) . Tuy nhiên...
    • D * -Lite (2002): Thuật toán này sử dụng LPA * để bắt chước D *; nghĩa là, nó sử dụng LPA * để tìm đường dẫn tốt nhất mới cho một đơn vị khi nó di chuyển dọc theo đường dẫn tốt nhất ban đầu và biểu đồ thay đổi. D * -Lite được coi là đơn giản hơn nhiều so với D *, và vì nó luôn chạy ít nhất là nhanh như D *, nên nó đã hoàn toàn lỗi thời D *. Vì vậy, không bao giờ có bất kỳ lý do để sử dụng D *; sử dụng D * -Lite thay thế.
  • Chuyển động góc bất kỳ
    • Trường D * (2007): Một biến thể của D * -Lite không hạn chế chuyển động thành lưới; nghĩa là, đường dẫn tốt nhất có thể có đơn vị di chuyển dọc theo bất kỳ góc nào, không chỉ 45- (hoặc 90-) độ giữa các điểm lưới. Đã được NASA sử dụng để tìm đường cho những người đi trên sao Hỏa.
    • Theta * (2007): Một biến thể của A * cung cấp các đường dẫn tốt hơn (ngắn hơn) so với Trường D *. Tuy nhiên, vì nó dựa trên A * chứ không phải D * -Lite, nên nó không có khả năng phục hồi nhanh như Trường D *. Xem thêm .
    • Incremental Phi * (2009): Điều tốt nhất của cả hai thế giới. Một phiên bản của Theta * tăng dần (hay còn gọi là cho phép thay thế nhanh)
  • Di chuyển điểm mục tiêu
    • GAA * (2008): GAA * (Thích ứng tổng quát A *) là một biến thể của A * xử lý các điểm mục tiêu đang di chuyển. Đó là một khái quát của một thuật toán thậm chí còn sớm hơn được gọi là "Di chuyển mục tiêu thích ứng A *"
    • GRFA * (2010): GFRA * (Generalized Fringe-Retrieving A *) xuất hiện (?) Để khái quát hóa GAA * thành các biểu đồ tùy ý (nghĩa là không giới hạn ở 2D) bằng cách sử dụng các kỹ thuật từ thuật toán khác gọi là FRA *.
    • MTD * -Lite (2010): MTD * -Lite (Di chuyển mục tiêu D * -Lite) là "phần mở rộng của D * Lite sử dụng nguyên tắc đằng sau Tổng quát hóa Fringe-Lấy A *" để thực hiện tìm kiếm mục tiêu di chuyển nhanh.
    • Tree-AA * (2011): (???) Xuất hiện là một thuật toán để tìm kiếm địa hình không xác định, nhưng dựa trên Thích ứng A *, giống như tất cả các thuật toán khác trong phần này, vì vậy tôi đặt nó ở đây. Không chắc làm thế nào nó so sánh với những người khác trong phần này.
  • Nhanh / tối ưu
    • Bất cứ lúc nào D * (2005): Đây là biến thể "Bất kỳ lúc nào" của D * -Lite, được thực hiện bằng cách kết hợp D * -Lite với một thuật toán gọi là Anytime Repair A * . Thuật toán "Bất cứ lúc nào" là thuật toán có thể chạy trong bất kỳ ràng buộc thời gian nào - nó sẽ tìm thấy một đường dẫn rất tối ưu rất nhanh để bắt đầu, sau đó cải thiện theo đường dẫn đó càng nhiều thời gian hơn.
    • HPA * (2004): HPA * (Tìm đường dẫn phân cấp A *) dành cho tìm đường dẫn một số lượng lớn các đơn vị trên biểu đồ lớn, chẳng hạn như trong các trò chơi video RTS (chiến lược thời gian thực) . Tất cả họ sẽ có vị trí bắt đầu khác nhau và có khả năng vị trí kết thúc khác nhau. HPA * chia biểu đồ thành một hệ thống phân cấp để nhanh chóng tìm thấy các đường dẫn "gần tối ưu" cho tất cả các đơn vị này nhanh hơn nhiều so với việc chạy A * trên từng đơn vị riêng lẻ. Xem thêm
    • PRA * (2005): Theo những gì tôi hiểu, PRA * (Sàng lọc một phần A *) giải quyết vấn đề tương tự như HPA *, nhưng theo một cách khác. Cả hai đều có "đặc điểm hiệu suất tương tự."
    • HAA * (2008): HAA * (Phân cấp chú thích A *) là một khái quát của HPA * cho phép di chuyển hạn chế một số đơn vị trên một số địa hình (ví dụ: một con đường nhỏ mà một số đơn vị có thể đi qua nhưng những đơn vị lớn hơn không thể đi qua; hoặc một lỗ mà chỉ các đơn vị bay có thể vượt qua, v.v.)
  • Khác / Không biết
    • LPA (1997): LPA (Thuật toán tìm đường không vòng lặp) dường như là một thuật toán định tuyến chỉ liên quan đến các vấn đề mà các thuật toán khác ở đây giải quyết. Tôi chỉ đề cập đến nó bởi vì bài báo này gây nhầm lẫn (và không chính xác) được tham chiếu trên một số nơi trên Internet như bài báo giới thiệu LPA *, mà nó không phải là.
    • LEARCH (2009): LEARCH là sự kết hợp của các thuật toán học máy, được sử dụng để dạy cho robot cách tự tìm các đường dẫn gần tối ưu. Các tác giả đề nghị kết hợp TÌM KIẾM với Trường D * để có kết quả tốt hơn.
    • BDDĐ * (2009): ??? Tôi không thể truy cập vào bài báo.
    • SetA * (2002): ??? Đây rõ ràng là một biến thể của A * tìm kiếm trên mô hình "sơ đồ quyết định nhị phân" (BDD) của đồ thị? Họ cho rằng nó chạy "một số đơn đặt hàng có cường độ nhanh hơn A *" trong một số trường hợp. Tuy nhiên, nếu tôi hiểu chính xác, những trường hợp đó là khi mỗi nút trên biểu đồ có nhiều cạnh?

Với tất cả điều này, có vẻ như LPA * là phù hợp nhất cho vấn đề của tôi.


Chà .. tôi cũng tìm thấy bài báo này của @lhrios , so sánh một số thuật toán.
mg007

Tôi biết điều này đã cũ, nhưng tôi nghĩ rằng đáng chú ý là một lỗ hổng nhỏ trong mô tả của bạn về Trường D *. D * thông thường không bị ràng buộc với "lưới", nó bị ràng buộc vào một biểu đồ riêng. Điểm mà bài báo đưa ra là để làm cho A *, D * vv hoạt động, bạn phải phân tách một không gian liên tục thành các khối, điều này hạn chế các góc bạn có thể di chuyển. Trường D * loại bỏ ràng buộc đó và cho phép bạn xử lý các trạng thái kế tiếp một cách liên tục, thay vì rời rạc (ít nhiều, có liên quan đến mánh khóe). Nó chỉ đơn giản là sử dụng lưới 2D làm ví dụ, D * / A * vv không có nghĩa là bị ràng buộc với lưới.
Tuyến tínhZoetrope

Tôi nên đề cập rằng Trường D * được giới hạn trong một lưới, mặc dù bài báo đề cập rằng chúng đã hoạt động trên phiên bản 3D. Điều này là do nội suy nó sử dụng. Vẫn có ý kiến ​​cho rằng A * và D * hoạt động trên các biểu đồ với số lượng trạng thái kế tiếp tùy ý, Trường D * chỉ là một cải tiến cho các tình huống trong đó D * sử dụng lập kế hoạch dựa trên lưới.
Tuyến tínhZoetrope

Một sự khác biệt quan trọng giữa Trường D * và Theta * / Incremental Phi *, đó là Trường D * có thể có trọng số duy nhất cho mỗi ô vuông, trong khi Theta * và Phi tăng * được giới hạn có cùng trọng số cho tất cả các ô vuông có thể được truy cập. Do đó, Phi * tăng không vượt trội so với Trường D *.
HelloGoodbye

1
@Jsor: Đây là phiên bản 3D của Trường D *: Trường 3D D - JPL Robotics
Hellooodbye

16

Có một sự cảnh báo lớn khi sử dụng D *, D * -Lite hoặc bất kỳ thuật toán gia tăng nào trong danh mục này (và đáng chú ý là cảnh báo này hiếm khi được đề cập trong tài liệu). Các loại thuật toán sử dụng một tìm kiếm đảo ngược. Đó là, họ tính toán chi phí từ nút mục tiêu, giống như một gợn sóng lan ra bên ngoài. Khi chi phí của các cạnh thay đổi (ví dụ: bạn thêm hoặc xóa tường trong ví dụ của mình), tất cả chúng đều có các chiến lược hiệu quả khác nhau để chỉ cập nhật tập hợp con của các nút được khám phá (còn gọi là 'đã truy cập') bị ảnh hưởng bởi các thay đổi.

Nhắc nhở lớn là vị trí của những thay đổi này liên quan đến vị trí mục tiêu tạo ra sự khác biệt rất lớn đối với hiệu quả của các thuật toán. Tôi đã trình bày trong nhiều bài báo và luận điểm của mình rằng hiệu suất trong trường hợp xấu nhất của bất kỳ thuật toán gia tăng nào là tồi tệ hơn việc vứt bỏ tất cả thông tin và bắt đầu từ một thứ không tăng dần như A * cũ.

Khi thông tin chi phí thay đổi gần với chu vi của mặt trận tìm kiếm mở rộng (vùng 'đã truy cập'), một vài đường dẫn phải thay đổi và các cập nhật gia tăng nhanh chóng. Một ví dụ thích hợp là một robot di động với các cảm biến được gắn vào cơ thể của nó. Các cảm biến chỉ nhìn thấy thế giới gần robot, và do đó những thay đổi nằm ở khu vực này. Vùng này là điểm bắt đầu của tìm kiếm, không phải là mục tiêu và vì vậy mọi thứ đều hoạt động tốt và các thuật toán rất hiệu quả trong việc cập nhật đường dẫn tối ưu để điều chỉnh các thay đổi.

Khi thông tin chi phí thay đổi gần với mục tiêu tìm kiếm (hoặc kịch bản của bạn nhìn thấy các vị trí thay đổi mục tiêu, không chỉ là bắt đầu), các thuật toán này phải chịu sự chậm chạp thảm khốc. Trong kịch bản này, hầu hết tất cả các thông tin đã lưu cần được cập nhật, vì vùng thay đổi rất gần với mục tiêu mà hầu như tất cả các đường dẫn được tính toán trước đều đi qua các thay đổi và phải được đánh giá lại. Do chi phí lưu trữ thêm thông tin và tính toán để thực hiện cập nhật gia tăng, việc đánh giá lại trên thang đo này chậm hơn so với khởi đầu mới.

Vì kịch bản ví dụ của bạn xuất hiện để cho phép người dùng di chuyển bất kỳ bức tường nào họ muốn, bạn sẽ gặp phải vấn đề này nếu bạn sử dụng D *, D * -Lite, LPA *, v.v. Hiệu suất thời gian của thuật toán của bạn sẽ thay đổi, phụ thuộc vào người dùng đầu vào. Nói chung, "đây là một điều xấu" ...

Lấy ví dụ, nhóm của Alonzo Kelly tại CMU đã có một chương trình tuyệt vời có tên là PerceptOR, cố gắng kết hợp robot mặt đất với robot trên không, tất cả đều chia sẻ thông tin nhận thức trong thời gian thực. Khi họ cố gắng sử dụng một máy bay trực thăng để cung cấp cập nhật chi phí thời gian thực cho hệ thống kế hoạch của một phương tiện mặt đất, họ đã gặp phải vấn đề này vì máy bay trực thăng có thể bay phía trước phương tiện mặt đất, thấy chi phí thay đổi gần mục tiêu hơn và do đó làm chậm xuống thuật toán của họ. Họ đã thảo luận về quan sát thú vị này? Cuối cùng, điều tốt nhất họ quản lý là để chiếc trực thăng bay thẳng trên đầu của phương tiện mặt đất - biến nó thành cột cảm biến đắt nhất thế giới. Chắc chắn, tôi đang nhỏ mọn. Nhưng đó là một vấn đề lớn mà không ai muốn nói đến - và họ nên,

Chỉ có một số ít các bài báo thảo luận về điều này, chủ yếu là do tôi. Trong số các bài báo được viết bởi các tác giả hoặc sinh viên của các tác giả của các bài báo gốc được liệt kê trong câu hỏi này, tôi chỉ có thể nghĩ về một bài viết thực sự đề cập đến vấn đề này. Likhachev và Ferguson đề nghị cố gắng ước tính quy mô của các cập nhật cần thiết và xóa thông tin được lưu trữ nếu cập nhật gia tăng được ước tính sẽ mất nhiều thời gian hơn một khởi đầu mới. Đây là một cách giải quyết khá hợp lý, nhưng cũng có những người khác. Tiến sĩ của tôi khái quát một cách tiếp cận tương tự trên một loạt các vấn đề tính toán và đang vượt ra ngoài phạm vi của câu hỏi này, tuy nhiên bạn có thể thấy các tài liệu tham khảo hữu ích vì nó có cái nhìn tổng quan về hầu hết các thuật toán này và hơn thế nữa. Xem http://db.acfr.usyd.edu.au/doad.php/ ALLen2011_Tribution.pdf? Id = 364 để biết chi tiết.


1
Cảm ơn bạn đã thêm các chi tiết này :) Trong ứng dụng của tôi, bức tường được di chuyển về phía đầu thường xuyên như về cuối. Tôi đã triển khai BFS, A * và LPA *; A * thực sự chậm hơn một chút so với BFS (không gian của tôi có xu hướng bị giới hạn, vì vậy A * chỉ tìm kiếm ít nút hơn BFS một chút, trong khi đó BFS chỉ cần một hàng đợi, có thể được triển khai nhanh hơn so với hàng đợi ưu tiên) , nhưng sử dụng LPA * trung bình nhanh hơn gấp đôi.
BlueRaja - Daniel Pflughoeft

9

Ý tưởng chính là sử dụng thuật toán gia tăng, có thể tận dụng các tính toán trước đó khi tuyến tính toán ban đầu bị chặn. Điều này thường được điều tra trong bối cảnh robot, điều hướng và lập kế hoạch.

Koenig & Likkachev, Bổ sung nhanh cho Điều hướng trong Địa hình không xác định, Giao dịch của IEEE về Robotics, Tập. 21, số 3, tháng 6 năm 2005 giới thiệu D * Lite. Có vẻ an toàn khi nói rằng D * đã lỗi thời theo nghĩa là D * Lite luôn nhanh như D *. Ngoài ra, D * là phức tạp, khó hiểu, phân tích và mở rộng. Hình 9 đưa ra mã giả cho D * Lite và Bảng 1 cho thấy kết quả thử nghiệm với D * Lite so với BFS, Backward A *, Forward A *, DynamicSWSF-P và D *.

Tôi không biết các thuật toán mới hơn mà bạn liệt kê (Bất kỳ lúc nào D *, Trường D *, TÌM KIẾM). Gần đây tôi thấy một robot sử dụng D * Lite để lập kế hoạch trong một môi trường có người đi bộ ngẫu nhiên trong đó. Theo nghĩa này, tôi không nghĩ D * Lite đã lỗi thời. Đối với vấn đề thực tế của bạn, tôi đoán không có hại gì khi thử cách kỹ thuật thông thường: thực hiện một số cách tiếp cận và nếu nó không phù hợp với nhu cầu của bạn, hãy thử một cái gì đó khác (phức tạp hơn).


4

Tôi muốn thêm một cái gì đó về việc khám phá nhanh các cây ngẫu nhiên hoặc RRT. Ý tưởng cơ bản có thảo luận tốt trên internet, nhưng có lẽ an toàn khi bắt đầu với các liên kết ngoài trang Wikipedia và với các bài viết gốc của Kuffner và LaValle về chủ đề này.

Tính năng quan trọng nhất của RRT là chúng có thể xử lý các không gian có giá trị thực có kích thước cực cao mà không bị nghẹt thở. Chúng có thể xử lý động lực học, không tối ưu nhưng hoàn thành về mặt xác suất (được đảm bảo thành công nếu có thể vì thời gian tính toán đến vô cùng) và có khả năng xử lý các mục tiêu di chuyển. Có một số tiện ích mở rộng cho phép chúng hoạt động trong các không gian không tĩnh, trong đó tiện ích tốt nhất có vẻ là công việc RRT đa tầng mà tôi đã liên kết bên dưới.


0

Cấu trúc dữ liệu được gọi là orials khoảng cách xử lý các vấn đề như vậy. Tuy nhiên, hầu hết các kết quả nghiên cứu chỉ dành cho đồ thị tĩnh .

Nếu các biểu đồ là lưới (và do đó là mặt phẳng), một số cấu trúc dữ liệu động tồn tại (không rõ liệu các hằng số có đủ nhỏ cho ứng dụng được đề cập không):

Đường dẫn ngắn nhất chính xác:

Jittat Fakcharoenphol, Satish Rao: Đồ thị phẳng, cạnh trọng lượng âm, đường đi ngắn nhất và gần thời gian tuyến tính. J. Tính toán. Hệ thống. Khoa học. 72 (5): 868-889 (2006)

Đường dẫn ngắn nhất gần đúng:

Philip N. Klein, Sairam Subramanian: Một lược đồ xấp xỉ hoàn toàn động cho các đường đi ngắn nhất trong đồ thị phẳng. Thuật toán 22 (3): 235-249 (1998)

Ittai Abraham, Shiri Chechik, Cyril Gavoille: Các nhà tiên tri khoảng cách gần đúng hoàn toàn năng động cho các đồ thị phẳng thông qua các nhãn khoảng cách được đặt. STOC 2012: 1199-1218


Xin lỗi, nhưng nếu chúng chỉ hoạt động trên các biểu đồ tĩnh, thì bạn có ý gì khi "chúng xử lý các vấn đề như vậy?" Vấn đề được hỏi cụ thể là về đồ thị không tĩnh.
BlueRaja - Daniel Pflughoeft

hãy để tôi thay đổi sự nhấn mạnh: hầu hết các kết quả chỉ dành cho biểu đồ tĩnh. một số cấu trúc dữ liệu động tồn tại. theo sau là một danh sách các cấu trúc dữ liệu động.
Christian Sommer

0

Ở trường, tôi đã học được cách tối ưu hóa đàn kiến . Trong một số văn bản, nó được quảng cáo là một giải pháp để liên tục thay đổi đồ thị, mạng định tuyến, v.v. Nó không phải là một giải pháp kỹ thuật, mà là sự thích nghi từ cách kiến ​​di chuyển xung quanh chướng ngại vật bằng cách truyền pheromone để đánh dấu đường đi tốt và xấu. Tôi không biết nó có hiệu quả với vấn đề của bạn không, nhưng tôi nghĩ đó là một quan điểm thú vị.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.