Python入门习题(76)——OpenJudge百练习题:判断多个点是否在同一直线
题目描述
来源
OpenJudge网站 – 百练习题集-第4072号习题
要求
总时间限制: 1000ms 内存限制: 65536kB
描述
有N(1<=N<=100)个互不重合的点,并给出它们的坐标(xi,yi),问这些点是否在同一直线上。
输入
第一行是测试的组数T(1<=T<=100),其后是T组数据,每组数据第一行是该组数据点的数量N,后面跟着N行,每行代表一点的坐标,由两个数字构成,这两个数字之间由空格隔开。
输出
有T行,每行对应输入的一组数据,如果该组数据中的点在同一直线上,则该行输出True,否则输出False。
样例输入
1
3
0 0
2 2
1 1
样例输出
True
解题思路
- 学过三角函数的人在解答本题的时候,比较自然地想到判断斜率是否一致的做法。然而,这一做法有弊病有二:一是斜率可能无穷大,计算机存不了。二是,当两个坐标点落在垂直直线上时,dx等于0。
- 上述方法变通一下,比如在斜率很大的时候,改为判断斜率的倒数是否一致的做法。加入这一变通,代码逻辑变得更加复杂,而且事实上,由于两个坐标点可以任意组合,可能出现有两个点连成的直线的斜率无穷大,又有两个点连成的直线的斜率的倒数无穷大,问题依旧存在。
- 我们采用的做法是判断直线与横坐标轴的夹角的右向正弦值是否一致。计算两个点(x1, y1)和(x2, y2)的右向正弦值步骤是:
(3-1)如果x1等于x2,则右向正弦值 = 1。
(3-2)如果x1>x2,则令dy = y1 - y2;如果x1 <= x2,则dy = y2 - y1。右向正弦值 = dy / - 这道题有一个坑,就是坐标点只有一个的时候,视为处于同一条直线上。对这一点,不是百分百肯定。
参考答案
import math
ERROR_LIMIT = 10 ** -9
#求两个坐标点的右向正弦值
def right_sin(point_a,point_b):
delta_x = point_a[0] - point_b[0]
if delta_x == 0:
return 1
elif delta_x < 0:
delta_x = -delta_x
delta_y = point_b[1] - point_a[1]
else:
delta_y = point_a[1] - point_b[1]
distance_sqrt = math.sqrt(delta_x * delta_x + delta_y * delta_y)
return delta_y / distance_sqrt
#points内的点处在同一条直线上吗?
#points内至少有3个点。
def on_one_line(points):
sin_1 = right_sin(points[0], points[1])
for j in range(2, point_num):
sin_j = right_sin(points[0], points[j])
if math.fabs(sin_1 - sin_j) > ERROR_LIMIT:
return False
return True
T = int(input())
for i in range(T):
point_num = int(input())
points = [[int(s) for s in input().split()] for j in range(point_num)]
if point_num == 2:
print("True")
continue
elif point_num == 1:
print("True")
continue
if on_one_line(points):
print("True")
else:
print("False")
测试用例
-
题目描述给出的测试用例的坐标点都处于坐标系的第一象限。
-
坐标点都落在水平直线上。
样例输入
1
5
0 0
2 0
1 0
-10 0
22 0
样例输出
True -
坐标点都落在垂直直线上。
样例输入
1
5
-1 0
-1 10
-1 20
-1 33
-1 -8
样例输出
True -
坐标点不在一条直线上。
样例输入
1
5
-1 0
-2 10
-1 20
0 33
-1 -8
样例输出
False -
两组测试数据。
样例输入
2
3
-1 0
-2 10
-1 20
3
0 0
2 2
1 1
样例输出
False
True -
一个点构成直线。
样例输入
1
1
-1 0
样例输出
True -
两个点必定构成直线。
样例输入
1
2
-1 0
44 99
样例输出
True -
有的点落在斜45度,有的点落在斜 -45度直线上。
样例输入
1
5
0 0
1 1
-1 1
2 2
2 -2
样例输出
Fasle -
坐标点都落在斜45度线上。
样例输入
1
5
0 0
1 1
-1 -1
2 2
-2 -2
样例输出
True -
dx和dy交叉相等。
样例输入
1
3
0 0
1 2
2 1
样例输出
False
小结
- 判断右向正弦值是否一致比判断斜率是否一致更好。右向正弦值是正弦值,但它是有特殊要求的正弦值。定义见解题思路一节。
- 把判断一组点是否在同一直线上的过程抽取成函数,是好做法。不抽取成函数的话,将有双重循环,内循环有两种结束情形,要加以甄别,加大了代码逻辑的复杂度。