cf598 C. Nearest vectors(極角排序、比較角的大小)
阿新 • • 發佈:2022-04-04
題意:
給定n個起點都為0的向量,找出一對夾角最小的
輸入均為整數
思路:
這題如果用atan2做極角排序,要開long double。正解是全程不用浮點數。
用叉積做極角排序,注意要判象限。這裡定義角度範圍 \((-pi,pi]\),所以 y負半軸 要排在末尾。
角的大小比較:設向量 \(v,u\) 的夾角是 \(\theta\),想辦法旋轉兩個向量,使 \(u\) 與 x正半軸重合。那麼新的向量終點是 \((|v|\cos(\theta),|v|\sin(\theta))\)。可以用縱座標/橫座標來衡量它的大小,即 \(v,u\) 的叉積除以點積。注意我們要讓 \(v\) 在 \(u\) 的上方,所以叉積要取絕對值
struct point { ll x, y; int id; }; ll dot(point a, point b) { return a.x * b.x + a.y * b.y; } ll cross(point a, point b) { return a.x * b.y - a.y * b.x; } bool below(point a) { //(pi,pi],y負半軸是最大值 return a.y < 0 || a.y == 0 && a.x > 0; } bool polarLess(point a, point b) { if(below(a) != below(b)) return below(a); return cross(a, b) > 0; } bool angleLess(point a1, point b1, point a2, point b2) { point t1 = {abs(cross(a1, b1)), dot(a1, b1)}; //絕對值 point t2 = {abs(cross(a2, b2)), dot(a2, b2)}; return cross(t1, t2) < 0; } const int N = 1e5 + 3; int n; point a[N]; signed main() { iofast; cin >> n; for(int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y, a[i].id = i; sort(a + 1, a + 1 + n, polarLess); int ans1 = n, ans2 = 1; for(int i = 1; i < n; i++) if(angleLess(a[i], a[i+1], a[ans1], a[ans2])) ans1 = i, ans2 = i+1; cout << a[ans1].id << ' ' << a[ans2].id; }