Вектор деген не?
Вектор — бағыты және ұзындығы бар объект.
Жазықтықта vector көбіне екі coordinate арқылы беріледі:
v = (x, y)
Мысалы:
v = (3, 4)
Бұл vector 3 бірлік оңға және 4 бірлік жоғары қарай жүреді деген сөз.
Екі нүкте арасындағы vector
Екі нүкте берілсін:
A = (x1, y1)
B = (x2, y2)
Онда A-дан B-ға vector:
AB = (x2 - x1, y2 - y1)
Мысал:
A = (2, 1)
B = (7, 4)
AB = (7 - 2, 4 - 1) = (5, 3)
Point struct
Geometry задачаларында point пен vector-ды бірдей struct арқылы сақтау ыңғайлы.
struct Point {
long long x;
long long y;
};
Егер Point point координатасын сақтаса, екі point-тың айырмасы vector береді.
Vector операциялары
Операторлар қосуға болады:
struct Point {
long long x;
long long y;
Point operator + (const Point &other) const {
return {x + other.x, y + other.y};
}
Point operator - (const Point &other) const {
return {x - other.x, y - other.y};
}
Point operator * (long long k) const {
return {x * k, y * k};
}
};
Енді былай жазуға болады:
Point c = a + b;
Point v = b - a;
Point t = v * 3;
Vector қосу
Егер:
a = (x1, y1)
b = (x2, y2)
Онда:
a + b = (x1 + x2, y1 + y2)
Мысал:
(2, 3) + (5, 1) = (7, 4)
Vector азайту
Егер:
a = (x1, y1)
b = (x2, y2)
Онда:
a - b = (x1 - x2, y1 - y2)
Мысал:
(7, 4) - (2, 3) = (5, 1)
Vector-ды санға көбейту
Vector-ды санға көбейтсек, оның координаталары да сол санға көбейеді.
k * (x, y) = (k * x, k * y)
Мысал:
3 * (2, 5) = (6, 15)
Vector ұзындығы
v = (x, y) vector-ының length:
|v| = sqrt(x^2 + y^2)
Мысал:
v = (3, 4)
|v| = sqrt(3^2 + 4^2) = 5
Length коды
double length(Point v) {
return sqrt(v.x * v.x + v.y * v.y);
}
Квадрат length
Квадрат length:
|v|^2 = x^2 + y^2
Код:
long long length2(Point v) {
return v.x * v.x + v.y * v.y;
}
Бұл ыңғайлы, себебі:
- sqrt жоқ
- double error жоқ
- тез жұмыс істейді
Екі point арасындағы distance
A және B point-тары арасындағы distance — бұл B - A vector-ының length-і.
double dist(Point a, Point b) {
return length(b - a);
}
Квадрат distance:
long long dist2(Point a, Point b) {
return length2(b - a);
}
Скалярлық көбейтінді
Скалярлық көбейтінді, немесе dot product:
dot(a, b) = a.x * b.x + a.y * b.y
Код:
long long dot(Point a, Point b) {
return a.x * b.x + a.y * b.y;
}
dot нені көрсетеді?
Dot екі vector арасындағы angle-ды түсінуге көмектеседі.
dot(a, b) = 0 → angle 90°
dot(a, b) < 0 → angle доғал
Сондықтан dot көбіне perpendicular тексеру үшін қолданылады.
Перпендикулярлық
Екі vector perpendicular болады, егер:
dot(a, b) = 0
Код:
bool perpendicular(Point a, Point b) {
return dot(a, b) == 0;
}
Мысал:
a = (1, 0)
b = (0, 1)
dot(a, b) = 0
Vector арасындағы angle
Екі vector арасындағы angle dot арқылы табылады:
cos(angle) = dot(a, b) / (|a| * |b|)
Код:
double angle(Point a, Point b) {
double value = dot(a, b) / (length(a) * length(b));
value = max(-1.0, min(1.0, value));
return acos(value);
}
Векторлық көбейтінді
2D geometry ішінде векторлық көбейтінді, немесе cross product:
cross(a, b) = a.x * b.y - a.y * b.x
Код:
long long cross(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}
cross нені көрсетеді?
Cross бірінші vector-дан екінші vector-ға бұрылғанда direction көрсетеді.
cross(a, b) < 0 → b, a-ның оң жағында
cross(a, b) = 0 → vector-лар бір түзудің бойында
Бұл turn, orientation және segment intersection задачалары үшін ең маңызды операция.
Коллинеар vector-лар
Екі vector collinear болады, егер олар бір түзудің бойында жатса.
Шарт:
cross(a, b) = 0
Код:
bool collinear(Point a, Point b) {
return cross(a, b) == 0;
}
Үш point orientation-ы
A, B, C үш point үшін C point-ы бағытталған AB segment-іне қатысты қай жерде тұрғанын табуға болады.
Есептейміз:
cross(B - A, C - A)
< 0 → C AB-ның оң жағында
= 0 → A, B, C бір түзуде
Orientation коды
long long orient(Point a, Point b, Point c) {
return cross(b - a, c - a);
}
Қолдану мысалы:
long long val = orient(a, b, c);
if (val > 0) {
cout << "LEFT";
} else if (val < 0) {
cout << "RIGHT";
} else {
cout << "COLLINEAR";
}
Area cross арқылы
Cross модулі екі vector құрған parallelogram area-сына тең.
area_parallelogram = abs(cross(a, b))
Triangle area одан 2 есе кіші:
area_triangle = abs(cross(a, b)) / 2
ABC triangle area
A, B, C point-тары үшін:
area2 = abs(cross(B - A, C - A))
Бұл екі еселенген area.
Код:
long long triangleArea2(Point a, Point b, Point c) {
return abs(cross(b - a, c - a));
}
Vector-ды 90 градусқа бұру
Егер vector:
v = (x, y)
Онда 90 градусқа сағат тіліне қарсы бұру:
(-y, x)
90 градусқа сағат тілімен бұру:
(y, -x)
Код: 90 градусқа бұру
Point rotate90Left(Point v) {
return {-v.y, v.x};
}
Point rotate90Right(Point v) {
return {v.y, -v.x};
}
Бұл perpendicular vector алу үшін жиі қолданылады.
Кез келген angle-ға бұру
Vector-ды angle бұрышына бұру керек болса, sin және cos қолданамыз.
newX = x * cos(angle) - y * sin(angle)
newY = x * sin(angle) + y * cos(angle)
Код:
struct DPoint {
double x;
double y;
};
DPoint rotate(DPoint p, double angle) {
double cs = cos(angle);
double sn = sin(angle);
return {
p.x * cs - p.y * sn,
p.x * sn + p.y * cs
};
}
Vector projection
a vector-ының b vector-ына projection-ы — a-ның қанша бөлігі b direction бойынша жатқанын көрсетеді.
Projection length:
dot(a, b) / |b|
Егер нақты формула керек болса, көбіне double қолданамыз.
Polar angle бойынша sort
Кейде point-тарды немесе vector-ларды origin-ге қатысты angle бойынша sort жасау керек.
Оңай әдіс — atan2 қолдану:
double getAngle(Point p) {
return atan2(p.y, p.x);
}
Sort:
sort(a.begin(), a.end(), [](Point p1, Point p2) {
return atan2(p1.y, p1.x) < atan2(p2.y, p2.x);
});
Vector нормализациясы
Кейде vector-ды unit length-ке келтіру керек. Бұл нормализация деп аталады.
unit = v / |v|
Бұл үшін double керек:
DPoint normalize(DPoint v) {
double len = sqrt(v.x * v.x + v.y * v.y);
return {v.x / len, v.y / len};
}
Zero vector
Zero vector:
(0, 0)
Оның length-і 0. Оның direction-ы жоқ.
Тексеру:
bool isZero(Point v) {
return v.x == 0 && v.y == 0;
}
Толық базалық template
#include <bits/stdc++.h>
using namespace std;
struct Point {
long long x;
long long y;
Point operator + (const Point &other) const {
return {x + other.x, y + other.y};
}
Point operator - (const Point &other) const {
return {x - other.x, y - other.y};
}
Point operator * (long long k) const {
return {x * k, y * k};
}
};
long long dot(Point a, Point b) {
return a.x * b.x + a.y * b.y;
}
long long cross(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}
long long orient(Point a, Point b, Point c) {
return cross(b - a, c - a);
}
long long length2(Point v) {
return v.x * v.x + v.y * v.y;
}
double length(Point v) {
return sqrt(length2(v));
}
long long dist2(Point a, Point b) {
return length2(b - a);
}
double dist(Point a, Point b) {
return length(b - a);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
Point a, b;
cin >> a.x >> a.y;
cin >> b.x >> b.y;
Point v = b - a;
cout << v.x << ' ' << v.y << '\n';
cout << length(v) << '\n';
return 0;
}
Мысал
Input
2 1
7 4
Output
5 3
5.83095
Мұнда:
A = (2, 1)
B = (7, 4)
AB = (5, 3)
dot қашан қолданылады?
angle сүйір ме, доғал ма білу керек → dot sign
angle табу керек → acos через dot
projection керек → dot
direction салыстыру керек → dot
cross қашан қолданылады?
collinear тексеру керек → cross == 0
area табу керек → abs(cross)
segment intersection тексеру керек → orient арқылы cross
convex hull құру керек → cross
long long немесе double?
| Тип | Қашан қолданамыз? |
|---|---|
| long long | coordinates integer, нақты dot/cross/orient керек |
| double | length, angle, sin, cos, sqrt керек |
double үшін EPS
Double сандарды == арқылы салыстыру қауіпті. Кішкентай error болуы мүмкін.
const double EPS = 1e-9;
int cmp(double x) {
if (x > EPS) {
return 1;
}
if (x < -EPS) {
return -1;
}
return 0;
}
Егер cmp(x) == 0 болса, x нөлге тең деп есептейміз.
Типтік задачалар
- vector length табу
- екі point арасындағы distance табу
- perpendicular тексеру
- collinear тексеру
- солға немесе оңға turn анықтау
- triangle area табу
- point-тарды angle бойынша sort жасау
- segment intersection тексеру
Типтік қателер
- point пен vector-ды шатастыру
- AB vector үшін B - A орнына A - B жазу
- dot пен cross шатастыру
- cross әрқашан positive деп ойлау
- coordinates үлкен кезде int қолдану
- length2 арқылы салыстыруға болатын жерде sqrt алу
- double-ды == арқылы салыстыру
- zero vector нормализация жасау
Асимптотика
| Операция | Уақыт |
|---|---|
| Vector қосу | O(1) |
| Vector азайту | O(1) |
| Vector length | O(1) |
| dot | O(1) |
| cross | O(1) |
| orientation | O(1) |
| Angle бойынша sort | O(n log n) |
Қысқа template
struct Point {
long long x;
long long y;
Point operator - (const Point &other) const {
return {x - other.x, y - other.y};
}
};
long long dot(Point a, Point b) {
return a.x * b.x + a.y * b.y;
}
long long cross(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}
long long orient(Point a, Point b, Point c) {
return cross(b - a, c - a);
}
long long length2(Point v) {
return v.x * v.x + v.y * v.y;
}
Ең бастысы
AB = B - A
length = sqrt(x² + y²)
dot angle көрсетеді
cross turn көрсетеді
cross == 0 → collinear
dot == 0 → perpendicular