範例程式碼已於UVA
、瘋狂程設(CPE)
、ZeroJudge
上皆測試通過。
題意
給定平行四邊形中兩條 相鄰 邊的端點座標,求不屬於這兩條邊的最後一個點的座標。
LuckyCat 的中文翻譯
思路:數學(Math) + 幾何與座標 + 計數(Counter)
這題利用了「平行四邊形中對角座標相加會相等」的性質,即 D = B + C − A D = B + C - A D = B + C − A ,可以利用 向量 來證明。
為方便說明,令重複點為 A A A ,即給定的兩條邊為 A B → \overrightarrow{AB} A B 和 A C → \overrightarrow{AC} A C ,最後一個點為 D D D ;令 O O O 為原點,則 A A A 的座標即為 O A → \overrightarrow{OA} O A
欲證 O A → + O D → = O B → + O C → \overrightarrow{OA} + \overrightarrow{OD} = \overrightarrow{OB} + \overrightarrow{OC} O A + O D = OB + OC ,即 O D → = O B → + O C → − O A → \overrightarrow{OD} = \overrightarrow{OB} + \overrightarrow{OC} - \overrightarrow{OA} O D = OB + OC − O A
由於是平行四邊形,所以 A D → = A B → + A C → \overrightarrow{AD} = \overrightarrow{AB} + \overrightarrow{AC} A D = A B + A C
而 O B → = O A → + A B → \overrightarrow{OB} = \overrightarrow{OA} + \overrightarrow{AB} OB = O A + A B 、 O C → = O A → + A C → \overrightarrow{OC} = \overrightarrow{OA} + \overrightarrow{AC} OC = O A + A C ,代入 O B → + O C → − O A → \overrightarrow{OB} + \overrightarrow{OC} - \overrightarrow{OA} OB + OC − O A 中,得 ( O A → + A B → ) + ( O A → + A C → ) − O A → = O A → + A B → + A C → = O A → + A D → = A D → (\overrightarrow{OA} + \overrightarrow{AB}) + (\overrightarrow{OA} + \overrightarrow{AC}) - \overrightarrow{OA} = \overrightarrow{OA} + \overrightarrow{AB} + \overrightarrow{AC} = \overrightarrow{OA} + \overrightarrow{AD} = \overrightarrow{AD} ( O A + A B ) + ( O A + A C ) − O A = O A + A B + A C = O A + A D = A D ,得證。
這題可以利用 Counter
來計算每個點的出現次數,出現兩次的點即為重複點,也就是上述的 A A A 點。在計算時遇到重複點時,減去該點的座標;反之則加上該點的座標,即可得到最後一個點的座標。
但由於出現次數只有兩次,也可以直接檢查四個點中重複的點是哪兩個,總共有 C 2 4 = 6 C^4_2 = 6 C 2 4 = 6 種組合,但顯然同一條邊上的兩點不會重複,所以只需要檢查 4 4 4 種組合即可。
時間複雜度:O ( 1 ) O(1) O ( 1 ) ,對於每次詢問。
空間複雜度:O ( 1 ) O(1) O ( 1 ) ,只需要常數空間。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from collections import *while (True ): try : P = list (map (float , input ().split())) if len (P) != 8 : break except : break cnt = Counter() for i in range (4 ): x, y = P[i * 2 ], P[i * 2 + 1 ] cnt[(x, y)] += 1 x, y = 0 , 0 for (dx, dy), v in cnt.items(): x += dx if v == 1 else -dx y += dy if v == 1 else -dy print (f"{x:.3 f} {y:.3 f} " )
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 #include <bits/stdc++.h> using namespace std;#define endl "\n" int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); double x1, y1, x2, y2, x3, y3, x4, y4; while (cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4) { double x = 0 , y = 0 ; if (x1 == x3 && y1 == y3) { x = x2 + x4 - x1; y = y2 + y4 - y1; } else if (x1 == x4 && y1 == y4) { x = x2 + x3 - x1; y = y2 + y3 - y1; } else if (x2 == x3 && y2 == y3) { x = x1 + x4 - x2; y = y1 + y4 - y2; } else if (x2 == x4 && y2 == y4) { x = x1 + x3 - x2; y = y1 + y3 - y2; } cout << fixed << setprecision (3 ) << x << " " << y << endl; } return 0 ; }
寫在最後
Cover photo is remixed from @Tiffany , thanks for their work!