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;
}

posted @ 2022-04-04 20:51  Bellala  阅读(97)  评论(0)    收藏  举报