Задача
Два отрезка на плоскости заданы целочисленными координатами своих концов в декартовой системе координат.
Требуется определить, существует ли у них общая точка.
Входные данные
В первой строке содержатся координаты первого конца первого отрезка, во второй — второго конца первого отрезка, в третьей и четвёртой — координаты концов второго отрезка. Координаты целые и по модулю не превосходят $10000$.
Выходные данные
Вывести слово $Yes$, если общая точка есть, или слово $No$ в противном случае.
Тесты
№ | Входные данные | Выходные данные |
1 | 0 0 1 0 1 0 1 1 |
Yes |
2 | 0 0 1 0 2 0 3 0 |
No |
3 | 7 4 1 1 1 1 3 2 |
Yes |
4 | -9725 -8992 9812 9925 -9999 7011 8122 -9248 |
Yes |
5 | -9999 -1 10000 1 0 0 0 1 |
No |
Код программы
С ветвлением:
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#include <iostream> #include <cmath> #define E 1e-5 using namespace std; double length(double x1, double y1, double x2, double y2){ return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } bool is_include(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, double x, double y){ return ( abs(length(x1, y1, x, y) - length(x1, y1, x2, y2) + length(x, y, x2, y2)) <= E && abs(length(x3, y3, x, y) - length(x3, y3, x4, y4) + length(x, y, x4, y4)) <= E ); } bool is_overlap(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { return( abs(length(x1, y1, x3, y3) - length(x1, y1, x2, y2) + length(x3, y3, x2, y2)) <= E || abs(length(x1, y1, x4, y4) - length(x1, y1, x2, y2) + length(x4, y4, x2, y2)) <= E || abs(length(x3, y3, x1, y1) - length(x3, y3, x4, y4) + length(x1, y1, x4, y4)) <= E || abs(length(x3, y3, x2, y2) - length(x3, y3, x4, y4) + length(x2, y2, x4, y4)) <= E ); } int main() { long x1, y1, x2, y2, x3, y3, x4, y4; double x, y; cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4; long long ky1, kx1, b1, ky2, kx2, b2; ky1 = y2 - y1; ky2 = y4 - y3; kx1 = x2 - x1; kx2 = x4 - x3; b1 = x1 * y2 - x2 * y1; b2 = x3 * y4 - x4 * y3; if (kx1 * ky2 == kx2 * ky1) { if ( b1 * ky2 != b2 * ky1 && b1 * kx2 != b2 * kx1 ) cout << "No"; else if (is_overlap(x1, y1, x2, y2, x3, y3, x4, y4)) cout << "Yes"; else cout << "No"; } else { y = (double)(b2 * ky1 - b1 * ky2) / (double)(kx1 * ky2 - kx2 * ky1); x = (double)(b1 * kx2 - b2 * kx1) / (double)(ky1 * kx2 - ky2 * kx1); if (is_include(x1, y1, x2, y2, x3, y3, x4, y4, x, y)) cout << "Yes"; else cout << "No"; } return 0; } |
без ветвления:
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#include <iostream> #include <cmath> #define E 1e-5 using namespace std; double length(double x1, double y1, double x2, double y2){ return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } bool is_include(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, double x, double y){ return ( abs(length(x1, y1, x, y) - length(x1, y1, x2, y2) + length(x, y, x2, y2)) <= E && abs(length(x3, y3, x, y) - length(x3, y3, x4, y4) + length(x, y, x4, y4)) <= E ); } bool is_overlap(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { return( abs(length(x1, y1, x3, y3) - length(x1, y1, x2, y2) + length(x3, y3, x2, y2)) <= E || abs(length(x1, y1, x4, y4) - length(x1, y1, x2, y2) + length(x4, y4, x2, y2)) <= E || abs(length(x3, y3, x1, y1) - length(x3, y3, x4, y4) + length(x1, y1, x4, y4)) <= E || abs(length(x3, y3, x2, y2) - length(x3, y3, x4, y4) + length(x2, y2, x4, y4)) <= E ); } int main() { long x1, y1, x2, y2, x3, y3, x4, y4; double x, y; cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4; long long ky1, kx1, b1, ky2, kx2, b2; ky1 = y2 - y1; ky2 = y4 - y3; kx1 = x2 - x1; kx2 = x4 - x3; b1 = x1 * y2 - x2 * y1; b2 = x3 * y4 - x4 * y3; (kx1 * ky2 == kx2 * ky1) && ( ( b1 * ky2 != b2 * ky1 && b1 * kx2 != b2 * kx1 ) && (cout << "No") || (is_overlap(x1, y1, x2, y2, x3, y3, x4, y4)) && (cout << "Yes") || (cout << "No") ) || ( y = (double)(b2 * ky1 - b1 * ky2) / (double)(kx1 * ky2 - kx2 * ky1), x = (double)(b1 * kx2 - b2 * kx1) / (double)(ky1 * kx2 - ky2 * kx1), (is_include(x1, y1, x2, y2, x3, y3, x4, y4, x, y)) && (cout << "Yes") || (cout << "No") ); return 0; } |
Решение задачи
Чтобы проверить пересекаются ли заданные отрезки построим прямые, которым они принадлежат, затем найдём точку их пересечения и проверим принадлежит ли она каждому из отрезков.
Для построения прямых воспользуемся формулой прямой проходящей через две точки и немного её преобразуем:
$\frac{x — x_1}{x_2 — x_1} = \frac{y — y_1}{y_2 — y_1}$ ~ $(x — x_1) \cdot (y_2 — y_1) = (y — y_1) \cdot (x_2 — x_1)$ ~ $x \cdot (y_2 — y_1) — y_2 \cdot x_1 + y_1 \cdot x_1 = y \cdot (x_2 — x_1) — x_2 \cdot y_1 + x_1 \cdot y_1$ ~ $y \cdot (x_2 — x_1) = x \cdot (y_2 — y_1) + x_2 \cdot y_1 — x_1 \cdot y_2$.
Обозначим за $k_x$ множитель при $x$, за $k_y$ множитель при $y$, а всё остальное за $b$. Тогда имеем уравнение вида:
$y \cdot k_y = x \cdot k_x + b$, таких у нас будет 2:
- $y \cdot k_{y_1} = x \cdot k_{x_1} + b_1$
- $y \cdot k_{y_2} = x \cdot k_{x_2} + b_2$
Теперь рассмотрим несколько случаев:
1. Прямые параллельны, следовательно могут не иметь точки пересечения или совпадать.
Проверим совпадают ли $b_1$ и $b_2$. Так как уравнения не сокращены на НОД, то рассмотрим равенство отношений $b_1$ и $b_2$ на $k_{y_1}$, $k_{x_1}$ и $k_{y_2}$, $k_{x_2}$ соответственно. Если они равны, то прямые совпадают. Иначе не имеют точек пересечения, а следовательно и отрезки тоже не пересекаются.
Когда прямые совпадают, необходимо проверить, что отрезки на этой прямой имеют хоть какую-то общую точку. Каждый из концов каждого отрезка проверим на вхождение в другой. Если такое вхождение есть, то отрезки пересекаются, иначе нет.
2. Прямые не параллельны, а следовательно имеют точку пересечения.
Тогда, решив систему двух линейных уравнений в общем виде получим что:
- $x = \frac{b_1 \cdot k_{x_2} — b_2 \cdot k_{x_1}}{k_{y_1} \cdot k_{x_2} — k_{x_1} \cdot k_{y_2}}$
- $y = \frac{b_2 \cdot k_{y_1} — b_1 \cdot k_{y_2}}{k_{x_1} \cdot k_{y_2} — k_{y_1} \cdot k_{x_2}}$
Осталось проверить находится ли точка с координатами $(x, y)$ в каждом из отрезков. Для этого просуммируем расстояния от этой точки до границ каждого отрезка и сравним с длинами отрезков. Если суммы соответственно совпали с длинами, то отрезки пересекаются, иначе — нет.