cf598 C. Nearest vectors(极角排序、比较角的大小)
题意:
给定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) {
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;
}

浙公网安备 33010602011771号