Trong bài viết phần 1 về chủ đề Hình học tính toán, chúng ta đã cùng nghiên cứu về cách sử dụng vector trong các bài toán hình học. Còn trong bài viết này, tôi sẽ giới thiệu những vấn đề liên quan tới đường thẳng, giao điểm và sử dụng kiến thức về đại số tuyến tính để tính toán giao điểm, tính toán diện tích, qua đó áp dụng trong những bài toán hình học của lập trình thi đấu.
Trong Toán học phổ thông, các bạn đã biết có nhiều cách để biểu diễn một đường thẳng, vì thế cũng có nhiều cách biểu diễn đường thẳng trong máy tính, mà tùy vào dữ kiện đề bài ta sẽ chọn cách biểu diễn phù hợp. Dưới đây là một số cách biểu diễn đường thẳng thường dùng trong các bài toán Tin học:
Khi cần chuyển đổi giữa các biểu diễn, ta thực hiện biến đổi tương đương đại số, kết hợp với công thức chuyển đổi giữa vector chỉ phương d⃗(−b,a)vec{d}(-b, a)d(−b,a) và vector pháp tuyến n⃗(a,b)vec{n}(a, b)n(a,b).
Đây là bài toán phổ biến nhất trong các bài toán về giao điểm, nhưng không phải ai cũng có thể thực hiện thành thạo.
Trong trường hợp lý tưởng, ta sẽ có được hai đường thẳng đều được biểu diễn ở dạng Ax+By=CAx + By = CAx+By=C với A,B,CA, B, CA,B,C là các hệ số xác định đường thẳng. Tuy nhiên, không phải lúc nào bài toán cũng tuyệt đẹp như vậy. Nhưng may mắn rằng, ta có thể dễ dàng tìm được biểu diễn tổng quát trên dựa vào hai điểm cho trước thuộc đường thẳng. Ví dụ có hai điểm phân biệt (x1,y1)(x_1,y_1)(x1,y1) và (x2,y2),(x_2,y_2),(x2,y2), và để tìm A,B,CA,B,CA,B,C cho phương trình trên, ta có công thức:
Đường thẳng dù ở dạng nào, ta cũng có thể chọn được hai điểm phân biệt thuộc đường thẳng và dùng công thức trên để tính A,B,CA, B, CA,B,C.
Giờ, coi như ta đã thu được hai đường thẳng được cho bởi hai phương trình:
{A1x+B1y=C1 (1)A2x+B2y=C2 (2)begin{cases}A_1x + B_1y = C_1 (1) A_2x + B_2y = C_2 (2) end{cases} {A1x+B1y=C1 (1)A2x+B2y=C2 (2)
Để tìm giao điểm của hai đường thẳng, ta chỉ cần giải hệ phương trình hai ẩn x,yx, yx,y. Cách làm như sau:
{A1B2x+B1B2y=B2C1A2B1x+B1B2y=B1C2begin{cases}A_1B_2x + B_1B_2y = B_2C_1 A_2B_1x + B_1B_2y = B_1C_2 end{cases} {A1B2x+B1B2y=B2C1A2B1x+B1B2y=B1C2
A1B2x+A2B1x=B2C1−B1C2A_1B_2x + A_2B_1x = B_2C_1 - B_1C_2 A1B2x+A2B1x=B2C1−B1C2
x=B2C1−B1C2A1B2−A2B1x = frac{B_2C_1 - B_1C_2}{A_1B_2 - A_2B_1} x=A1B2−A2B1B2C1−B1C2
y=A1C2−A2C1A1B2−A2B1y = frac{A_1C_2 - A_2C_1}{A_1B_2 - A_2B_1} y=A1B2−A2B1A1C2−A2C1
Như vậy, ta thu được giao điểm của hai đường thẳng đã cho.
Bài toán tiếp theo là cho bốn điểm A,B,C,DA, B, C, DA,B,C,D trên mặt phẳng, cần xác định xem hai đoạn thẳng ABABAB và CDCDCD có giao điểm duy nhất hay không, nếu có thì đưa ra tọa độ của giao điểm đó.
Sử dụng những kiến thức về tích có hướng, ta có thể thực hiện công việc này không mấy khó khăn. Tuy nhiên, trước tiên cần phải xem xét liệu trong số bốn điểm đã cho, có tồn tại ba điểm nào thẳng hàng hay không.
Kiến thức các bạn cần lưu ý ở đây là: Với góc ααα thỏa mãn 0°<α<180°0°<α<180°0°<α<180° thì sin(α)>0sin(α)>0sin(α)>0 nên nếu góc ngược chiều kim đồng hồ θ<180°θ<180°θ<180° thì tích có hướng dương, ngược lại tích có hướng âm (đã đề cập ở bài viết trước).
Xét ba điểm A,B,C;A, B, C;A,B,C; Giả sử ta đi từ điểm AAA sang điểm BBB theo đường thằng và đi tiếp sang điểm CCC theo đường thẳng, khi đó:
Nếu tồn tại 333 trong 444 điểm đầu mút thẳng hàng, ta kiểm tra xem có tồn tại đầu mút của đoạn thẳng này thuộc đoạn thẳng kia hay không:
Nếu có thì rõ ràng là 222 đoạn thẳng giao nhau tại ít nhất 111 điểm (tại đầu mút vừa xét):
Nếu không thì rõ ràng là 2 đoạn thẳng không thể giao nhau:
Nếu không tồn tại 333 trong 444 điểm đầu mút thẳng hàng thì 222 đoạn thẳng ABABAB và CDCDCD giao nhau khi:
Để CCC và DDD nằm khác phía đối với đường thẳng AB thì:
Từ đó, ta có hệ sau:
Hình minh họa:
Ta biết rằng, từ ba điểm không thẳng hàng, luôn luôn tồn tại duy nhất một đường tròn đi qua ba điểm đó. Để tìm được tâm của đường tròn này, ta ứng dụng chính bài toán xác định giao điểm đường thẳng.
Quan sát hình vẽ dưới đây:
Giả sử ba điểm cho trước là X,Y,Z;X, Y, Z;X,Y,Z; ta sẽ tìm đường trung trực của hai đoạn XYXYXY và YZ,YZ,YZ, sau đó tìm giao điểm của hai đường trung trực này, đó sẽ chính là tâm của đường tròn đi qua ba điểm X,Y,ZX, Y, ZX,Y,Z.
Đường trung trực của một đoạn thẳng chính là đường thẳng vuông góc với đoạn thẳng tại trung điểm của nó. Để tìm đường trung trực của đoạn thẳng XY,XY,XY, ta làm như sau:
Bước 1: Viết phương trình đường thẳng XY,XY,XY, giả sử nó là Ax+By=CAx + By = CAx+By=C.
Bước 2: Tìm trung điểm MMM của đoạn XYXYXY bằng cách lấy trung bình cộng của 222 hoành độ và trung bình cộng của 222 tung độ.
Bước 3: Viết phương trình đường thẳng của đường thẳng vuông góc với đường thẳng XYXYXY có dạng là −Bx+Ay=D−Bx+Ay=D−Bx+Ay=D (xem hình vẽ).
Bước 4: Thay tọa độ của trung điểm MMM vào phương trình đường thẳng ở bước 333 để tìm DDD và xác định đường trung trực.
Với 222 điểm X(2,−3)X(2,−3)X(2,−3) và Y(1,0);Y(1,0);Y(1,0); để tìm đường trung trực của đoạn XY,XY,XY, ta thực hiện như sau:
{xM=xX+xY2=2+12=1.5yM=yX+yY2=−3+02=−1.5begin{cases}x_M = frac{x_X + x_Y}{2} = frac{2 + 1}{2} = 1.5 y_M = frac{y_X + y_Y}{2} = frac{-3 + 0}{2} = -1.5end{cases} {xM=2xX+xY=22+1=1.5yM=2yX+yY=2−3+0=−1.5
−1.5+3.(−1.5)=D⇔D=−6-1.5 + 3.(-1.5) = D Leftrightarrow D = -6 −1.5+3.(−1.5)=D⇔D=−6
Vậy phương trình đường trung trực của đoạn thẳng XYXYXY là: −x+3y=−6-x + 3y = -6−x+3y=−6.
Làm tương tự với đoạn thẳng YZ,YZ,YZ, ta sẽ có hai phương trình của hai đường trung trực, và có thể tìm giao điểm của chúng như đã đề cập ở trên.
Có khá nhiều công thức giải tích để tính diện tích tam giác, tùy vào dữ kiện đề bài cho mà ta có thể lựa chọn cách tính phù hợp. Dưới đây là một số cách thường dùng:
S=a+h2S = frac{a + h}{2} S=2a+h
S=ab×sinα2S = frac{ab times sin alpha}{2} S=2ab×sinα
S=p(p−a)(p−b)(p−c)S = sqrt{p(p - a)(p - b)(p - c)} S=p(p−a)(p−b)(p−c)
trong đó ppp là nửa chu vi của tam giác.S=∣(xB−xA)(yC−yA)−(xC−xA)(yB−yA)2∣S = left|frac{(x_B - x_A)(y_C - y_A) - (x_C - x_A)(y_B - y_A)}{2}right| S=∣∣2(xB−xA)(yC−yA)−(xC−xA)(yB−yA)∣∣
Ta đã biết rằng, đa giác là một đường gấp khúc khép kín. Trong lập trình, một đa giác sẽ được biểu diễn bằng một dãy các đỉnh liên tiếp nhau A1,A2,A3,…,AnA_1, A_2, A_3, dots, A_nA1,A2,A3,…,An với tọa độ xác định trên hệ tọa độ Descartes.
Khi đó, diện tích đại số (có thể âm hoặc dương) của một đa giác không tự cắt được tính bằng công thức:
S=(x1−x2)(y1+y2)+(x2−x3)(y2+y3)+⋯+(xn−x1)(yn+y1)2S = frac{(x_1 - x_2)(y_1 + y_2) + (x_2 - x_3)(y_2 + y_3) + cdots + (x_n - x_1)(y_n + y_1)}{2} S=2(x1−x2)(y1+y2)+(x2−x3)(y2+y3)+⋯+(xn−x1)(yn+y1)
Và diện tích của đa giác sẽ chính bằng giá trị ∣S∣|S|∣S∣.
Việc xét diện tích đại số của đa giác có thể giúp chúng ta xác định được các đỉnh của đa giác này đang được liệt kê theo chiều nào. Nếu diện tích đại số là số dương (S>0S > 0S>0) thì dãy các đỉnh được liệt kê theo chiều ngược chiều kim đồng hồ (và ngược lại).
Xét một phép tịnh tiến theo vector (a,b)(a, b)(a,b). Phép tịnh tiến này sẽ biến một điểm O(0,0)O(0, 0)O(0,0) thành điểm O′(a,b),O'(a, b),O′(a,b), điểm I(1,0)I(1, 0)I(1,0) sẽ biến thành điểm I′(a+1,b)I'(a + 1, b)I′(a+1,b) và điểm J(0,1)J(0, 1)J(0,1) sẽ biến thành điểm J′(a,b+1)J'(a, b + 1)J′(a,b+1).
Tổng quát, phép tịnh tiến theo vector (a,b)(a, b)(a,b) sẽ biến điểm (x,y)(x, y)(x,y) thành điểm (x‾,y‾);(overline{x}, overline{y});(x,y); trong đó:
{x‾=x+ay‾=y+bbegin{cases}overline{x} = x + a overline{y} = y + b end{cases} {x=x+ay=y+b
Cho trước điểm A(x,y);A(x, y);A(x,y); để quay điểm AAA ngược chiều kim đồng hồ một góc αalphaα quanh gốc tọa độ, ta sử dụng công thức:
{x′=xcosα−ysinαy′=ysinα+ycosαbegin{cases}x' = x cos alpha - y sin alpha y' = y sin alpha + y cos alphaend{cases} {x′=xcosα−ysinαy′=ysinα+ycosα
Tuy nhiên, cần lưu ý trong các ngôn ngữ lập trình, số đo góc sử dụng trong các hàm lượng giác sẽ là radian (rad) chứ không phải độ, do đó các bạn cần lưu ý công thức chuyển đổi giữa hai đơn vị này:
π rad=180°⇒{rad=độ×π180độ=rad×180πpi rad = 180° Rightarrow begin{cases} rad = frac{text{độ} times pi}{180} text{độ} = frac{rad times 180}{pi} end{cases} π rad=180°⇒{rad=180độ×πđộ=πrad×180
Ngoài ra, chúng ta cũng có thể xây dựng công thức quay một điểm AAA quanh một điểm CCC bất kì khác gốc tọa độ, bằng cách tịnh tiến hệ tọa độ sao cho điểm CCC trùng với gốc tọa độ, rồi lại thực hiện phép quay như đã nêu ở trên.
Cho 222 điểm A(1,4)A(1,4)A(1,4) và C(2,2),C(2,2),C(2,2), để quay AAA ngược chiều kim đồng hồ một góc 45°45°45° quanh C,C,C, ta thực hiện như sau:
{xB′=−1.cos45°−2.sin45°=−322yB′=−1.sin45°+2.cos45°=22begin{cases} x_{B'} = -1.cos 45° - 2.sin 45° = -frac{3sqrt{2}}{2} y_{B'} = -1.sin 45° + 2.cos 45° = frac{sqrt{2}}{2}end{cases} {xB′=−1.cos45°−2.sin45°=−232yB′=−1.sin45°+2.cos45°=22
Vậy quay A(1,4)A(1,4)A(1,4) ngược chiều kim đồng hồ một góc 45°45°45° quanh C(2,2),C(2,2),C(2,2), ta được điểm B(−32-2+2,2-2+2)B(−32-sqrt{2}+2,2-sqrt{2}+2)B(−32-2+2,2-2+2).
Để lấy đối xứng một điểm XXX qua một đường thẳng (trục đối xứng), ta tìm giao điểm YYY của trục đối xứng và đường thẳng vuông góc với trục đối xứng đi qua X,X,X, sau đó lấy X′X′X′ đối xứng với X qua YYY.
Cho điểm X(1,−3)X(1, -3)X(1,−3) và đường thẳng (d):4x−3y=−5;(d): 4x - 3y = -5;(d):4x−3y=−5; để tìm điểm X′X'X′ đối xứng với XXX qua (d),(d),(d), ta thực hiện như sau:
3.1+4.(−3)=D⇔D=−9⇔(d′):3xx+4y=−93.1 + 4.(-3) = D Leftrightarrow D = -9 Leftrightarrow (d'): 3xx + 4y = -9 3.1+4.(−3)=D⇔D=−9⇔(d′):3xx+4y=−9
{xY=B2C1−B1C2A1B2−A2B1=4.(−5)−(−3).(−9)4.4−3.(−3)=−4725=−1.88yY=A1C2−A2C1A1B2−A2B1=4.(−9)−3.(−5)4.4−3.(−3)=−2125=−0.84begin{cases}x_Y = frac{B_2C_1 - B_1C_2}{A_1B_2 - A_2B_1} = frac{4.(-5) - (-3).(-9)}{4.4 - 3.(-3)} = frac{-47}{25} = -1.88 y_Y = frac{A_1C_2 - A_2C_1}{A_1B_2 - A_2B_1} = frac{4.(-9) - 3.(-5)}{4.4 - 3.(-3)} = frac{-21}{25} = -0.84 end{cases} {xY=A1B2−A2B1B2C1−B1C2=4.4−3.(−3)4.(−5)−(−3).(−9)=25−47=−1.88yY=A1B2−A2B1A1C2−A2C1=4.4−3.(−3)4.(−9)−3.(−5)=25−21=−0.84
{xX′=2xY−xX=2.(−1.88)−1=−4.76yX′=2yY−yX=2.(−0.84)−(−3)=1.32begin{cases}x_{X'} = 2x_Y - x_X = 2.(-1.88) - 1 = -4.76 y_{X'} = 2y_Y - y_X = 2.(-0.84) - (-3) = 1.32end{cases} {xX′=2xY−xX=2.(−1.88)−1=−4.76yX′=2yY−yX=2.(−0.84)−(−3)=1.32
Hình minh họa:
struct Point { double x, y; Point() { x = y = 0.0; } Point(double x, double y) : x(x), y(y) {} Point operator + (const Point &a) const { return Point(x + a.x, y + a.y); } Point operator - (const Point &a) const { return Point(x - a.x, y - a.y); } Point operator * (double k) const { return Point(x * k, y * k); } Point operator / (double k) const { return Point(x / k, y / k); } }; // Ax + By = C. struct Line { double a, b, c; Line(double a = 0, double b = 0, double c = 0) : a(a), b(b), c(c) {} }; Point intersect(Line d1, Line d2) { double det = d1.a * d2.b - d2.a * d1.b; // det != 0 because d1 is perpendicular to d2 return Point((d2.b * d1.c - d1.b * d2.c) / det, (d1.a * d2.c - d2.a * d1.c) / det); } Point symmetry(Point X, Line d) { // the equation of a perpendicular line has the form: -Bx + Ay = D. double D = -d.b * X.x + d.a * X.y; Line d2 = Line(-d.b, d.a, D); Point Y = intersect(d, d2); Point X2 = Point(2 * Y.x - X.x, 2 * Y.y - X.y); return X2; }©️ Tác giả: Vũ Quế Lâm từ Viblo
Link nội dung: https://www.sachhayonline.com/giao-diem-2-duong-thang-a56307.html