题目描述
输入N个互不相同的二维整数坐标,求这N个坐标可以构成的正方形数量。[内积为零的的两个向量垂直]
输入描述
第一行输入为N,N代表坐标数量,N为正整数。N <= 100
之后的 K 行输入为坐标x y以空格分隔,x,y为整数,-10<=x, y<=10
输出描述
输出可以构成的正方形数量。
用例
输入
3
1 3
2 4
3 1
输出
0
说明
(3个点不足以构成正方形)
输入
4
0 0
1 2
3 1
2 -1
输出
1
二维坐标构成正方形数量计算
核心解题思路
该题的关键在于利用几何性质来高效判断正方形的存在。已知两个点((x_1,y_1))和((x_2,y_2)),根据正方形的几何特征,可通过向量旋转(90^{\circ})的方式计算出另外两个可能的对角点坐标。
向量(\overrightarrow{AB}=(x_2 - x_1, y_2 - y_1)),将其旋转(90{\circ})(顺时针或逆时针),得到新向量。若原向量为((a,b)),顺时针旋转(90{\circ})后为((b,-a)),逆时针旋转(90^{\circ})后为((-b,a))。基于此,根据已知两点计算出另外两个可能的对角点坐标,然后检查这两个点是否都存在于给定的坐标列表中。若存在,则说明这四个点可以构成一个正方形。由于每个正方形在遍历点对的过程中会被计算(4)次(不同的边作为起始边),所以最终结果需要除以(4)。
完整代码实现
# 定义一个函数来判断两个点是否相等
def are_points_equal(p1, p2):return p1[0] == p2[0] and p1[1] == p2[1]# 定义一个函数来检查一个点是否存在于点列表中
def point_exists(points, p):for point in points:if are_points_equal(point, p):return Truereturn False# 读取坐标数量
n = int(input())
coordinates = []# 读取坐标并存入列表
for _ in range(n):x, y = map(int, input().split())coordinates.append((x, y))square_count = 0# 遍历所有点对,检查是否能构成正方形
for i in range(n):x1, y1 = coordinates[i]for j in range(i + 1, n):x2, y2 = coordinates[j]# 计算两个可能的对角点x3, y3 = x1 - (y1 - y2), y1 + (x1 - x2)x4, y4 = x2 - (y1 - y2), y2 + (x1 - x2)p3 = (x3, y3)p4 = (x4, y4)if point_exists(coordinates, p3) and point_exists(coordinates, p4):square_count += 1# 计算另外两个可能的对角点x5, y5 = x1 + (y1 - y2), y1 - (x1 - x2)x6, y6 = x2 + (y1 - y2), y2 - (x1 - x2)p5 = (x5, y5)p6 = (x6, y6)if point_exists(coordinates, p5) and point_exists(coordinates, p6):square_count += 1# 每个正方形被计算了4次,因此结果需要除以4
print(square_count // 4)
算法原理解析
点相等判断函数 are_points_equal
该函数通过比较两个点坐标的(x)值和(y)值是否分别相等,来判断两个点是否为同一个点。若(p1)的(x)坐标等于(p2)的(x)坐标,且(p1)的(y)坐标等于(p2)的(y)坐标,则返回 True
,否则返回 False
。
点存在检查函数 point_exists
遍历给定的点列表 points
,对于列表中的每一个点,调用 are_points_equal
函数检查其是否与目标点 p
相等。若存在相等的点,则返回 True
,表示目标点存在于列表中;遍历结束仍未找到相等的点,则返回 False
。
主逻辑
- 读取坐标数量
n
和具体的坐标值并存入列表coordinates
。 - 两层循环遍历所有的点对 ((i, j))((i < j)):
- 根据当前点对的坐标 ((x_1,y_1)) 和 ((x_2,y_2)),通过向量旋转的几何原理计算出两组可能的对角点坐标(如
(x3,y3)
、(x4,y4)
和(x5,y5)
、(x6,y6)
)。 - 分别检查每组对角点是否都存在于
coordinates
列表中。若存在,则square_count
计数器加 (1)。
- 根据当前点对的坐标 ((x_1,y_1)) 和 ((x_2,y_2)),通过向量旋转的几何原理计算出两组可能的对角点坐标(如
- 由于每个正方形在遍历点对的过程中会被计算 (4) 次(不同的边作为起始边),所以最终结果
square_count
需要除以 (4) 得到实际的正方形数量。
示例解析
示例一(输入 (3) 个点)
输入:
3
1 3
2 4
3 1
在两层循环中,由于只有 (3) 个点,当外层循环 i
取到 (2)(索引从 (0) 开始)时,内层循环 j
从 (i + 1 = 3) 开始,而总共有 (3) 个点,索引最大为 (2),内层循环不会执行。因此,square_count
始终为 (0),最终输出 (0),符合 (3) 个点无法构成正方形的条件。
示例二(输入 (4) 个点能构成 (1) 个正方形)
输入:
4
0 0
1 2
3 1
2 -1
假设我们取点对 ((0,0)) 和 ((1,2)):
- 计算第一组对角点:
(x3 = 0 - (0 - 2) = 2),(y3 = 0 + (0 - 1) = -1),即 (p3 = (2,-1))
(x4 = 1 - (0 - 2) = 3),(y4 = 2 + (0 - 1) = 1),即 (p4 = (3,1))
检查发现 (p3) 和 (p4) 都存在于坐标列表中,square_count
加 (1)。 - 计算第二组对角点时(可能不符合条件,此处不详细展开)。
由于存在这样一组符合条件的对角点,且经过其他点对计算(可能重复计算同一个正方形的不同边),最终square_count
会累加到 (4)(因为每个正方形被计算 (4) 次),除以 (4) 后输出 (1)。
总结
此代码通过巧妙利用几何中向量旋转的性质,避免了复杂的四重循环判断所有四个点组合的方式,大大提高了计算效率。对于初学者来说,理解向量旋转与坐标计算的关系是关键。通过 are_points_equal
和 point_exists
函数实现了点的基本操作判断,主逻辑部分通过遍历点对并结合几何计算来统计正方形数量。这种方法不仅在代码实现上相对简洁,而且在算法效率上也有较好的表现,适用于给定规模((N <= 100))的坐标输入情况。通过对示例的分析,能更清晰地看到代码如何根据输入数据进行计算并得出正确结果,有助于深入理解整个算法流程。