Bài 64: Sắp Xếp Cực & Quét Góc¶
Tác giả: FPTOJ Team
Nội dung tham khảo từ: CP-Algorithms, VNOI Wiki
1. Sắp xếp cực (Polar Sort)¶
1.1 Ý tưởng¶
Sắp xếp các điểm theo góc từ một điểm gốc (thường là gốc tọa độ hoặc điểm có tung độ nhỏ nhất). Đây là bước quan trọng trong nhiều thuật toán hình học phức tạp (như tìm bao lồi Graham Scan).
Minh họa trực quan:
Dưới đây là một tập hợp điểm được xếp thứ tự tăng dần từ #1 đến #5 theo góc lượng giác của chúng so với điểm gốc \(O(0,0)\) (từ \(0\) đến \(2\pi\)):

1.2 Dùng atan2¶
Hàm atan2(y, x) trả về góc từ trục \(x\) dương, trong khoảng \((-\pi, \pi]\). Sắp xếp theo giá trị này.
1.3 Sắp xếp theo góc từ điểm任意¶
Chuyển tất cả điểm về tọa độ tương đối so với điểm gốc, rồi sắp xếp.
2. Quét góc (Angular Sweep)¶
2.1 Ý tưởng¶
Duyệt một góc quay từ \(0\) đến \(2\pi\), tại mỗi vị trí đếm số điểm nằm trong một phạm vi góc cho trước (thường là nửa đường tròn, tứ giác, ...).
2.2 Bài toán: Maximum points in a half-plane¶
Cho \(n\) điểm, tìm số điểm tối đa nằm trong một nửa mặt phẳng (bởi một đường thẳng đi qua gốc).
2.3 Giải pháp¶
Sắp xếp tất cả điểm theo góc. Với mỗi điểm \(i\), tìm số điểm nằm trong góc \([\theta_i, \theta_i + \pi)\) bằng binary search trên mảng góc đã sắp xếp (nhân đôi mảng để xử lý vòng tròn).
3. Bài toán: Maximum points in a circle¶
3.1 Phát biểu¶
Cho \(n\) điểm, tìm bán kính nhỏ nhất của đường tròn chứa ít nhất \(k\) điểm.
3.2 Giải pháp¶
Với mỗi điểm \(i\) làm tâm đường tròn: - Tính khoảng cách từ \(i\) đến tất cả điểm khác - Sắp xếp khoảng cách - Lấy bán kính = khoảng cách thứ \(k-1\)
4. Bài toán: Visible points từ một điểm¶
4.1 Phát biểu¶
Cho \(n\) điểm trên mặt phẳng và một điểm quan sát \(O\). Đếm số điểm "nhìn thấy" được từ \(O\), tức là không bị che bởi điểm khác trên cùng một tia.
4.2 Giải pháp¶
Sắp xếp các điểm theo góc từ \(O\). Các điểm cùng góc → chỉ đếm 1.
5. Bài toán: Minimum rotation angle¶
5.1 Phát biểu¶
Cho 2 vector \(A\) và \(B\). Tìm góc nhỏ nhất (radian) cần quay \(A\) để trùng \(B\).
5.2 Công thức¶
6. Bài tập luyện tập¶
Bài 1: Sắp xếp theo góc¶
Đề bài: Cho \(n\) điểm trên mặt phẳng. Sắp xếp chúng theo góc từ gốc tọa độ (từ trục \(x\) dương, ngược chiều kim đồng hồ). Nếu cùng góc, sắp theo khoảng cách tăng dần.
Input: - Dòng 1: số nguyên \(n\) \((1 \leq n \leq 10^5)\) - \(n\) dòng: 2 số nguyên \(x_i, y_i\) \((|x_i|, |y_i| \leq 10^4)\), không có điểm nào là gốc tọa độ
Output: In ra \(n\) dòng, mỗi dòng 2 số \(x, y\) sau khi sắp xếp.
Ví dụ:
| Input | Output |
|---|---|
41 1-1 11 -1-1 -1 |
1 1-1 1-1 -11 -1 |
Lời giải
Sắp xếp theo atan2(y, x), nếu bằng nhau thì theo \(x^2 + y^2\).
Bài 2: Maximum points trong nửa mặt phẳng¶
Đề bài: Cho \(n\) điểm trên mặt phẳng. Tìm số điểm tối đa nằm trong một nửa mặt phẳng (bởi một đường thẳng đi qua gốc tọa độ).
Input: - Dòng 1: số nguyên \(n\) \((1 \leq n \leq 10^5)\) - \(n\) dòng: 2 số nguyên \(x_i, y_i\) \((|x_i|, |y_i| \leq 10^4)\)
Output: Số điểm tối đa.
Ví dụ:
| Input | Output |
|---|---|
41 00 1-1 00 -1 |
2 |
Lời giải
Sắp xếp theo góc, dùng two pointers trên mảng góc nhân đôi.
Bài 3: Visible points¶
Đề bài: Cho \(n\) điểm và điểm quan sát \(O(a,b)\). Đếm số điểm "nhìn thấy" từ \(O\) (không bị che bởi điểm khác trên cùng một tia).
Input: - Dòng 1: 3 số nguyên \(n, a, b\) \((1 \leq n \leq 10^5)\) - \(n\) dòng: 2 số nguyên \(x_i, y_i\)
Output: Số điểm nhìn thấy.
Ví dụ:
| Input | Output |
|---|---|
4 0 01 12 23 31 0 |
2 |
Giải thích: (1,1), (2,2), (3,3) cùng tia → chỉ đếm 1. (1,0) tia khác → đếm 1. Tổng = 2.
Lời giải
Tính góc từ \(O\) đến mỗi điểm, đếm số góc khác nhau.
Bài 4: Minimum rotation angle¶
Đề bài: Cho 2 vector \(A(x_1,y_1)\) và \(B(x_2,y_2)\). Tìm góc nhỏ nhất (độ) cần quay \(A\) để trùng \(B\).
Input: 4 số thực \(x_1, y_1, x_2, y_2\)
Output: Góc nhỏ nhất (độ), làm tròn 4 chữ số thập phân.
Ví dụ:
| Input | Output |
|---|---|
1 0 0 1 |
90.0000 |
1 0 -1 0 |
180.0000 |
Lời giải
\(\theta = \min(|\theta_A - \theta_B|, 2\pi - |\theta_A - \theta_B|)\).