极角

  |  

摘要: 极角的原理和代码

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


本文首先介绍一下极角的知识点,和代码模板,之后解决力扣的一道相关题目 1610。

向量的极角

以原点 O 为极点,从 x 轴正方向转到当前向量的角度称为向量的极角([0, 2PI))。代码如下:

1
2
3
4
5
6
7
// 从 x 轴正方向转到当前向量的角度
double polar() const
{
// atan2 返回 (-PI, PI],修正为 [0,2PI)
// fmod 求两个实数相除的余数
return fmod(atan2(y, x) + 2 * PI, 2 * PI);
}

角度转弧度

角度与弧度的比率为 ratio = 45.0 / atan(1.0),需要用角度的时候可以用弧度乘以 ratio。

点集的极角排序

很多时候需要对点集排序,可以选定一个点作为极点,将点集中的点表示为向量,将这些向量按照其极角排序。


题目

给你一个点数组 points 和一个表示角度的整数 angle ,你的位置是 location ,其中 location = [posx, posy] 且 points[i] = [xi, yi] 都表示 X-Y 平面上的整数坐标。

最开始,你面向东方进行观测。你 不能 进行移动改变位置,但可以通过 自转 调整观测角度。换句话说,posx 和 posy 不能改变。你的视野范围的角度用 angle 表示, 这决定了你观测任意方向时可以多宽。设 d 为你逆时针自转旋转的度数,那么你的视野就是角度范围 [d - angle/2, d + angle/2] 所指示的那片区域。

对于每个点,如果由该点、你的位置以及从你的位置直接向东的方向形成的角度 位于你的视野中 ,那么你就可以看到它。

同一个坐标上可以有多个点。你所在的位置也可能存在一些点,但不管你的怎么旋转,总是可以看到这些点。同时,点不会阻碍你看到其他点。

返回你能看到的点的最大数目。

提示:

1
2
3
4
5
1 <= points.length <= 1e5
points[i].length == 2
location.length == 2
0 <= angle < 360
0 <= posx, posy, xi, yi <= 100

示例 1:

输入:points = [[2,1],[2,2],[3,3]], angle = 90, location = [1,1]
输出:3
解释:阴影区域代表你的视野。在你的视野中,所有的点都清晰可见,尽管 [2,2] 和 [3,3]在同一条直线上,你仍然可以看到 [3,3] 。

示例 2:
输入:points = [[2,1],[2,2],[3,4],[1,1]], angle = 90, location = [1,1]
输出:4
解释:在你的视野中,所有的点都清晰可见,包括你所在位置的那个点。

示例 3:
输入:points = [[1,0],[2,1]], angle = 13, location = [1,1]
输出:1
解释:如图所示,你只能看到两点之一。

算法:计算几何

给定的位置为极点,将与极点重合的点排除掉,共 c0 个。

对剩余点做极角排序,并记录各个点的极角。

将所得数组复制一份接在后面,记为 vec。将后半部分的极角加上 2PI

给定的角度从角度表示转为弧度表示。

在 vec 上用尺取法,i 每轮前进 1,j 按照角度限制前进,每一轮更新一次答案。

答案返回前加上 c0。

代码 (C++)

代码中的 Vector2 为向量的代码模板,参考文章 【模板】二维向量的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
struct Point
{
Vector2 vec;
double angle;
Point(Vector2 p=Vector2(0,0), double a=0.0):vec(p),angle(a){}
};

struct Cmp
{
bool operator()(const Point& p1, const Point& p2) const
{
return p1.angle < p2.angle;
}
};

class Solution {
public:
int visiblePoints(vector<vector<int>>& points, int angle, vector<int>& location) {
int n = points.size();
vector<Point> ps;
Vector2 O(location[0], location[1]);
int c0 = 0;
for(int i = 0; i < n; ++i)
{
double x = points[i][0];
double y = points[i][1];
if(fabs(x - O.x) < EPS && fabs(y - O.y) < EPS)
{
++c0;
continue;
}
ps.emplace_back(Vector2(x - O.x, y - O.y));
ps.back().angle = ps.back().vec.polar();
}
int m = ps.size();
sort(ps.begin(), ps.end(), Cmp());
ps.insert(ps.end(), ps.begin(), ps.end());
for(int i = m; i < m * 2; ++i)
ps[i].angle += PI * 2;
int i = 0;
int ans = 0;
int j = 0;
double ratio = (double)45.0 / atan(1.0);
double a = (double)angle / ratio;
while(i < m)
{
while(j < m * 2 && fabs(ps[j].angle - ps[i].angle) < a + EPS)
++j;
ans = max(ans, j - i);
++i;
}
return ans + c0;
}
};

Share