📅  最后修改于: 2023-12-03 15:07:33.497000             🧑  作者: Mango
这是一个ISRO CS 2009考试中的问题15,涉及到图形算法和数学方面的知识。
给出一个单位正方形,其左下角定位在坐标原点。现在将其旋转某个角度。如果旋转后的单位正方形不能包含原单位正方形的四个顶点,则称该旋转角度是“安全”的。现在给定一个界限角度 $0\le q\le90$,请编写一个程序,通过输入一个浮点数 $q$,输出 “YES” 或者 “NO” 表示该角度是否是安全的。
一个浮点数 $q(0\le q\le90)$,表示旋转角度。
如果给定角度是“安全”的,输出 “YES”,否则输出 “NO”。
30.0
YES
45.0
NO
本题涉及到旋转角度和坐标变换的知识,需要用到一些数学计算。
首先,我们可以画出一个旋转后的矩形来看一下其是否能包含原矩形的四个顶点。
如图,原矩形的四个顶点为 $A(0,0), B(0,1), C(1,1), D(1,0)$,矩形中心点为 $O(\frac{1}{2}, \frac{1}{2})$,旋转角度为 $q$,则旋转后的新矩形四个顶点为 $A',B',C',D'$。
我们可以通过坐标变换来求出旋转后的新矩形的四个顶点坐标。
例如,点 $A$ 在经过坐标变换后的点 $A'$ 坐标为:
$$x_{A'} = x_A \cos q + y_A \sin q$$
$$y_{A'} = -x_A \sin q + y_A \cos q$$
其他三个点的坐标变换公式类似,在此不再赘述。
当然,我们还需要用到一个较为基础的数学公式——向量点积。
向量 $\overrightarrow{AB}$ 和向量 $\overrightarrow{CD}$ 的点积公式为:
$$\overrightarrow{AB} \cdot \overrightarrow{CD} = |\overrightarrow{AB}| \times |\overrightarrow{CD}| \times \cos \theta$$
其中,$|\overrightarrow{AB}|$ 可以表示 $\overrightarrow{AB}$ 的长度。$\theta$ 为 $\overrightarrow{AB}$ 和 $\overrightarrow{CD}$ 夹角的余弦值,即:
$$\cos \theta = \frac{\overrightarrow{AB}\cdot\overrightarrow{CD}}{|\overrightarrow{AB}|\times|\overrightarrow{CD}|}$$
我们只需要计算出每个点与矩形中心的向量和矩形中心的横轴的向量的点积,再与矩形中心的横轴的向量的长度乘积比较,即可判断是否能够完全包含原矩形的四个顶点。
那么,我们可以按照上述思路,写出以下解题代码。
以下为Python代码实现,这里用到了 numpy 库来对二维矩阵进行向量运算。
import numpy as np
def is_safe_angle(q: float) -> str:
sin_q = np.sin(np.deg2rad(q))
cos_q = np.cos(np.deg2rad(q))
mat = np.array([[cos_q, sin_q], [-sin_q, cos_q]])
center = np.array([0.5, 0.5])
vertices = np.array([[0, 0], [0, 1], [1, 1], [1, 0]])
new_vertices = np.matmul(vertices - center, mat) + center
dot_products = np.array([new_vertices[i] @ (vertices[i] - center) for i in range(4)])
return "YES" if not (dot_products > 0).all() else "NO"
这里 is_safe_angle 函数接受一个浮点型参数 q,表示旋转角度,返回一个字符串,表示该旋转角度是否安全。
函数内部首先将输入的角度转换为对应的 $\sin$ 和 $\cos$ 值。然后,定义一个 $2\times2$ 的旋转矩阵 mat,并指定矩阵的第一行为 $[\cos q, \sin q]$,第二行为 $[-\sin q, \cos q]$。这里使用 numpy 库的 array 函数来构造矩阵。
然后,我们定义矩形的中心点坐标为 $[0.5, 0.5]$,定义原矩形的四个顶点坐标和空数组变量 vertices 和 new_vertices,分别通过向量运算计算出矩形的新坐标。首先,我们将原矩形的四个顶点坐标按列向量的形式表示,作为一个 $2\times4$ 的数组。使用 numpy 库的 matmul 函数进行矩阵相乘运算,即可得到新坐标。
最后,我们比较四个新坐标与对应原坐标与中心点向量的点积是否都小于等于 0,若是则返回 YES,否则返回 NO。
测试该函数:
>>> is_safe_angle(30.0)
'YES'
>>> is_safe_angle(45.0)
'NO'
>>> is_safe_angle(15.5)
'YES'
>>> is_safe_angle(70.5)
'NO'