題目描述
來源
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
小結
- 判斷右向正弦值是否一致比判斷斜率是否一致更好。右向正弦值是正弦值,但它是有特殊要求的正弦值。定義見解題思路一節。
- 把判斷一組點是否在同一直線上的過程抽取成函數,是好做法。不抽取成函數的話,將有雙重循環,內循環有兩種結束情形,要加以甄別,加大了代碼邏輯的複雜度。