Việc tìm bao lồi (Convex Hull) của một tập hợp các điểm trong không gian hai chiều là một bài toán quan trọng trong hình học tính toán và có nhiều ứng dụng thực tế. Một trong những thuật toán phổ biến để giải quyết bài toán này là thuật toán Graham Scan. Sau đây, chúng ta sẽ tìm hiểu cách cài đặt thuật toán này trong lập trình.
1. Ý tưởng của thuật toán
Thuật toán Graham Scan được thiết kế để xây dựng bao lồi từ một tập hợp các điểm bằng các bước cơ bản sau:
- Chọn điểm gốc (pivot point): Điểm có y thấp nhất. Nếu có nhiều điểm có y thấp nhất, chọn điểm có x thấp nhất trong số đó.
- Sắp xếp các điểm theo góc cực so với điểm gốc.
- Duyệt qua các điểm đã sắp xếp và xây dựng bao lồi bằng cách duy trì một ngăn xếp để theo dõi các điểm là đỉnh của bao lồi.
2. Chi tiết cài đặt
Dưới đây là cách cài đặt thuật toán Graham Scan trong ngôn ngữ lập trình Python.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"({self.x}, {self.y})"
# Tìm điểm gốc
def find_pivot(points):
pivot = points[0]
for p in points[1:]:
if (p.y < pivot.y) or (p.y == pivot.y and p.x < pivot.x):
pivot = p
return pivot
# Tính góc giữa hai điểm với điểm gốc
def polar_angle(p0, p1):
return (p1.y - p0.y) / (p1.x - p0.x) if p1.x != p0.x else float('inf')
# Kiểm tra xem ba điểm có tạo thành một vòng quay trái hay không
def ccw(p0, p1, p2):
return (p1.x - p0.x) * (p2.y - p0.y) > (p1.y - p0.y) * (p2.x - p0.x)
# Hàm chính cài đặt thuật toán Graham Scan
def graham_scan(points):
pivot = find_pivot(points)
points.sort(key=lambda p: (polar_angle(pivot, p), (p.x - pivot.x)**2 + (p.y - pivot.y)**2))
hull = [pivot]
for point in points:
while len(hull) > 1 and not ccw(hull[-2], hull[-1], point):
hull.pop()
hull.append(point)
return hull
# Các điểm đầu vào
points = [Point(0, 3), Point(2, 2), Point(1, 1), Point(2, 1), Point(3, 0), Point(0, 0), Point(3, 3)]
hull = graham_scan(points)
print("Các điểm tạo thành bao lồi là:")
for point in hull:
print(point)
3. Giải thích chi tiết
- Lớp Point: Xác định một điểm trong không gian hai chiều với các thuộc tính x và y.
- Chọn điểm gốc: Hàm
find_pivot
duyệt qua tất cả các điểm để tìm điểm có y thấp nhất (và x thấp nhất nếu có nhiều điểm có y bằng nhau). - Sắp xếp điểm theo góc cực: Hàm
polar_angle
tính toán góc giữa hai điểm so với điểm gốc. Các điểm sau đó được sắp xếp theo góc cực và khoảng cách từ điểm gốc. - Thuật toán chính: Hàm
graham_scan
sử dụng một ngăn xếp để theo dõi các điểm tạo thành bao lồi. Khi thêm mỗi điểm mới vào, chúng ta kiểm tra xem nó có tạo thành một góc quay trái với hai điểm trước đó hay không. Nếu không, loại bỏ điểm giữa khỏi ngăn xếp vì nó không thuộc bao lồi.
Qua đây, chúng ta đã có một cái nhìn tổng quan về cách cài đặt và hoạt động của thuật toán Graham Scan. Hy vọng rằng bài viết này sẽ giúp ích cho bạn trong việc áp dụng thuật toán này trong các dự án của mình.
Comments