Tác giả:
Reviewer:
Hình học mặc dù là một chủ đề hết sức phổ biến, song vẫn còn rất nhiều người không thích giải các bài toán hình học vì chúng khá khó chịu và lằng nhằng. Do đó, trong bài viết này, ta sẽ cùng tìm hiểu một vài khái niệm nhằm giúp cho các bài toán hình học trở nên bớt đáng sợ hơn.
Nếu đã nắm vững các khái niệm trong bài viết này, các bạn có thể chuyển sang phần 2.
Vector là một đối tượng có cả độ lớn và hướng. Hướng của vector là hướng từ điểm đầu đến điểm cuối của nó.
Một vector thường được biểu diễn bằng một tia (một đoạn thẳng có hướng), hoặc bằng đồ thị dưới dạng một mũi tên nối từ điểm đầu tới điểm cuối , và được ký hiệu là .
Trong hình học phẳng, vector
Ví dụ: một vector từ
Độ lớn của
Ví dụ: Độ lớn của
Có một số phép toán có thể thực hiện trên vector, đơn giản nhất là phép cộng trừ vector: bạn có thể cộng trừ 2 vector với nhau để được một vector mới.
Xuyên suốt bài viết, chúng ta sẽ dùng dấu cộng (+) và trừ (-) để biểu diễn cho phép cộng và trừ vector.
Giả sử ta có
Lưu ý: Thứ tự cộng các vector không quan trọng, cũng giống như phép cộng trên số (tính giao hoán).
Cho vector
Mỗi vector đều có vector đối, chẳng hạn vector đối của
Hiệu của vector
Nếu 2 vector có chung điểm đầu thì vector hiệu có hướng từ điểm cuối của
Nếu 2 vector có chung điểm cuối thì vector hiệu có hướng từ điểm đầu của
Nhấn vào đây để tương tác với hình trên Desmos.
Không như phép cộng trừ vector là tương đối trực quan và dễ hiểu, vector có 2 phép toán kém trực quan hơn là tích vô hướng (dot product) và tích có hướng (cross product).
Tích vô hướng có thể được định nghĩa bằng đại số hoặc hình học. 2 định nghĩa này là tương đương khi sử dụng tọa độ Descartes.
Tính tích vô hướng của 2 vector
Từ
Lưu ý: tích vô hướng không chỉ giới hạn trong hình học phẳng, nghĩa là ta có thể sử dụng tích vô hướng cho các vector có số chiều tuỳ ý, và đẳng thức trên vẫn đúng.
Tích có hướng là một phép nhân vector trong không gian ba chiều. Nó khác tích vô hướng ở chỗ kết quả thu được là một vector thay cho một vô hướng. Vector này vuông góc với mặt phẳng chứa 2 vector đầu vào của phép nhân.
Tích có hướng được định nghĩa bằng công thức:
|||
Nếu xét trong hình học phẳng thì vector kết quả lúc này vuông góc và có hướng đi vào/ra mặt phẳng đang xét, do đó ta có thể bỏ qua đặc điểm về hướng, và sử dụng tích có hướng như là một đại lượng vô hướng.
Tương tự tích vô hướng, tích có hướng trong không gian 2 chiều cũng có thể được định nghĩa bằng 2 cách:
Ta cũng có thể xác định dấu của tích có hướng bằng quy tắc bàn tay phải nhưng về bản chất thì cũng giống với việc xét góc theo chiều ngược kim đồng hồ.
Tính tích có hướng của 2 vector
Lưu ý: Một tích chất hữu dụng của tích có hướng trong hình học phẳng là
Do đó, diện tích của một tam giác còn bằng một nửa giá trị tuyệt đối của tích có hướng với 2 vector thành phần là 2 cạnh của tam giác.
Tìm khoảng cách giữa điểm và đường thẳng rất thường gặp trong các bài toán hình học.
Ví dụ bạn có 3 điểm
Mọi thứ trở nên phức tạp hơn một chút khi ta muốn tìm khoảng cách từ một đoạn thẳng đến một điểm. Trong trường hợp này, điểm gần nhất có thể là một trong hai đầu mút của đoạn thẳng thay vì là một điểm nào đó trên đường thẳng. Trong hình trên, điểm gần
Có vài cách khác nhau để xử lý trường hợp này, một trong số đó là tích vô hướng. Đầu tiên, kiểm tra xem điểm gần nhất trên đường thẳng
Tương tự, nếu
#define x first
#define y second
typedef pair<int, int> pii;
// Compute the dot product AB ⋅ AC
int dot(pii A, pii B, pii C) {
pii AB, AC;
AB.x = B.x - A.x;
AB.y = B.y - A.y;
AC.x = C.x - A.x;
AC.y = C.y - A.y;
return AB.x * AC.x + AB.y * AC.y;
}
// Compute the cross product AB x AC
int cross(pii A, pii B, pii C) {
pii AB, AC;
AB.x = B.x - A.x;
AB.y = B.y - A.y;
AC.x = C.x - A.x;
AC.y = C.y - A.y;
return AB.x * AC.y - AB.y * AC.x;
}
// Compute the distance from A to B
double distance(pii A, pii B) {
int dx = A.x - B.x;
int dy = A.y - B.y;
return sqrt(dx * dx + dy * dy);
}
// Compute the distance from AB to C
// if isSegment is true, AB is a segment, not a line.
double linePointDist(pii A, pii B, pii C, bool isSegment) {
double dist = abs(cross(A, B, C)) / distance(A, B);
if (isSegment) {
int dot1 = dot(B, A, C);
if (dot1 < 0) return distance(B, C);
int dot2 = dot(A, B, C);
if (dot2 < 0) return distance(A, C);
}
return dist;
}
Đoạn code trên là cách mà mọi người thường dùng và có lẽ khá là dài, bên dưới là viết lại có sử dụng struct trong C++.
typedef double db;
struct vec {
db x, y;
vec(db _x = 0, db _y = 0) : x(_x), y(_y) {}
db dot(const vec &other) { // Compute the dot product
return x * other.x + y * other.y;
}
db cross(const vec &other) { // Compute the cross product
return x * other.y - y * other.x;
}
db length() const {
return sqrt(x * x + y * y);
}
};
using point = vec; // or use 'typedef vec point'
vec operator - (const point &B, const point &A) { // vecAB = B - A
return vec(B.x - A.x, B.y - A.y);
}
// if isSegment is true, AB is a segment, not a line.
db linePointDist(const point &A, const point &B, const point &C, bool isSegment) {
db dist = abs((B - A).cross(C - A)) / (A - B).length();
if (isSegment) {
db dot1 = (A - B).dot(C - B);
if (dot1 < 0) return (B - C).length();
db dot2 = (B - A).dot(C - A);
if (dot2 < 0) return (A - C).length();
}
return dist;
}
Nếu bạn sử dụng C++ thì bạn nên tìm hiểu về struct và tự viết class/struct geo_2D của riêng mình. Nó sẽ giúp các bài toán hình học trở nên đơn giản hơn nhiều.
Học phải đi đôi với hành, do đó mình đề xuất cho các bạn Codeforces Gym 100168. Tuy đề bài trong gym được viết bằng tiếng Nga nhưng rất ngắn gọn và đi thẳng vào bài toán nên các bạn có thể dễ dàng google translate.
Bên dưới là một số bài tập có liên quan đến bài viết này, mình đã tóm tắt yêu cầu bài toán để các bạn có thể hiểu đề dễ dàng hơn.