日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

「笔记」极角排序

發布時間:2024/1/4 综合教程 30 生活家
生活随笔 收集整理的這篇文章主要介紹了 「笔记」极角排序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄直接計算極角利用叉乘CF598C Nearest vectorsABC225- E 7鳴謝

極角排序,就是平面上有若干點,選一點作為極點,那么每個點有極坐標 ((ho , heta)) ,將它們關于極角 ( heta) 排序。進行極角排序有兩種方法。

直接計算極角

我們知道極坐標和直角坐標轉換公式中有 ( an heta = frac{y}{x}),所以可以用 (arctan) 來計算。然而 (arctan) 的值域只有 ((-frac{pi}{2},frac{pi}{2})) ,而且當 (x=0) 時無定義,所以需要復雜的分類討論。

所幸 cmath 中有一個 atan2(y,x) 的函數可以直接計算 (x,y) 的極角,值域是 ((-pi, pi]),所以可以直接用,只不過需要留心第四象限的極角會比第一象限小。

using Points = vector<Point>;
double theta(auto p) { return atan2(p.y, p.x); } // 求極角
void psort(Points &ps, Point c = O)              // 極角排序
{
    sort(ps.begin(), ps.end(), [&](auto p1, auto p2) {
        return lt(theta(p1 - c), theta(p2 - c));
    });
}

如果想減少常數,可以提前算出每個點的極角。

利用叉乘

叉乘的正負遵循右手定則,按旋轉方向彎曲右手四指,則若拇指向上叉乘為正,拇指向下叉乘為負。也就是說,如果一個向量通過劣角旋轉到另一個向量的方向需要按逆時針方向,那么叉乘為正,否則叉乘為負。

僅靠叉乘是不能進行排序的,因為它不符合偏序關系的條件。如果定義 (vec{x} imes vec{y} < 0) 則 ( heta_{vec{x}} < heta_{vec{y}}),那么我們會發現通過不斷在坐標軸上旋轉,一個向量的極角最終會小于自己。但是在同一象限內計算叉乘是可以的,所以我們先比較象限再做叉乘。

int qua(auto p) { return lt(p.y, 0) << 1 | lt(p.x, 0) ^ lt(p.y, 0); }    // 求象限
void psort(Points &ps, Point c = O)                               // 極角排序
{
    sort(ps.begin(), ps.end(), [&](auto v1, auto v2) {
        return qua(v1 - c) < qua(v2 - c) || qua(v1 - c) == qua(v2 - c) && lt(cross(v1 - c, v2 - c), 0);
    });
}

我們用0、1、2、3來表示第一、二、三、四象限。

這種方法常數可能稍微大一點,但是精度比較好,如果坐標都是整數的話是完全沒有精度損失的。

CF598C Nearest vectors

直接用 atan2 函數算出每個點的極角,然后按照極角從小到大排序,依次比較相鄰兩個點的差值取最優。

/*
Work by: Suzt_ilymtics
Problem: 不知名屑題
Knowledge: 垃圾算法
Time: O(能過)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define LD long double
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 1e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;
const LD pi = acos(-1.0);

struct node {
    int x, y, id;
    LD p;
    bool operator < (const node &b) const { return p < b.p; }
}a[MAXN];

int n, ans1 = 0, ans2 = 0;
LD ans;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

int main()
{
	n = read();
	for(int i = 1; i <= n; ++i) {
	    a[i].x = read(), a[i].y = read(), a[i].id = i;
	    a[i].p = atan2(a[i].x, a[i].y); // atan2(x, y);
	    if(a[i].p < 0) a[i].p += 2 * pi;
    }
    sort(a + 1, a + n + 1);
    ans = a[1].p - a[n].p + 2 * pi;
    ans1 = a[1].id, ans2 = a[n].id;
    for(int i = 2; i <= n; ++i) {
        if(a[i].p - a[i - 1].p < ans) {
            ans = a[i].p - a[i - 1].p;
            ans1 = a[i - 1].id, ans2 = a[i].id;
        }
    }
    printf("%d %d
", ans1, ans2);
    return 0;
}

ABC225- E 7

把每個點 ((x,y)) 抽象成一個起點為 ((x,y-1)) 終點為 ((x - 1, y)) 的線段。

然后我們就能算出這些點的極角,按照右端點排序,就轉化成了在序列上去最多段不相交的區間的問題,直接貪心即可。

/*
Work by: Suzt_ilymtics
Problem: 不知名屑題
Knowledge: 垃圾算法
Time: O(能過)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define LD long double
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 2e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;
const LD eps = 1e-10;

struct node {
    LD l, r;
    node () {}
    node (LD a, LD b) { l = a, r = b; }
    bool operator < (const node &b) const { return r < b.r; }
}a[MAXN];

int n, ans = 0;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

LD Tangent(LD x, LD y) {
    if(fabs(x) <= eps) return 1e15;
    return y / x;
}

int main()
{
	n = read();
	for(int i = 1; i <= n; ++i) {
	    LD x, y;
	    scanf("%Lf%Lf", &x, &y);
	    a[i] = node(Tangent(x, y - 1), Tangent(x - 1, y));
    }
    sort(a + 1, a + n + 1);
    LD lst = 0;
    for(int i = 1; i <= n; ++i) {
        if(a[i].l >= lst) {
            ans ++, lst = a[i].r;
        }
    }
    printf("%d", ans);
    return 0;
}

鳴謝

算法學習筆記(64): 極角排序

總結

以上是生活随笔為你收集整理的「笔记」极角排序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。