Обмежуючий прямокутник геометричної фігури — це найменший прямокутник, сторони якого паралельні осям координат, який повністю містить дану фігуру.
Простіше кажучи, якщо ми хочемо "вписати" фігуру в прямокутник так, щоб усі її точки були всередині, обмежуючий прямокутник буде найменшого розміру.
Розглянемо відрізок з кінцями в точках (x_1, y_1) і (x_2, y_2). Щоб знайти його обмежуючий прямокутник:
Визначимо лівий нижній кут прямокутника:
Визначимо правий верхній кут прямокутника:
Таким чином, обмежуючий прямокутник — це прямокутник з кутами (x_1', y_1') і (x_2', y_2'), який містить наш відрізок.
Лема. Нехай на прямій задано два відрізки (x_1, x_2) і (x_3, x_4), де x_1 < x_2 і x_3 < x_4. Відрізки не перетинаються тоді і тільки тоді, коли або перший відрізок розташований лівіше другого, або другий розташований лівіше першого.
Лема. Нехай на площині задано два прямокутника (x_1, y_1) - (x_2, y_2) і (x_3, y_3) - (x_4, y_4), де x_1 < x_2, y_1 < y_2 і x_3 < x_4, y_3 < y_4. Прямокутники не перетинаються тоді і тільки тоді, коли або не перетинаються відрізки (x_1, x_2) і (x_3, x_4), або не перетинаються відрізки (y_1, y_2) і (y_3, y_4).
Критерій перетину двох відрізків
Два відрізки і перетинаються тоді і тільки тоді, коли виконуються три умови:
1. Обмежуючі прямокутники перетинаються.
2. Точки і знаходяться по різні сторони від прямої або хоча б одна точка чи лежить на прямій . Це значить, що
3. Точки і знаходяться по різні сторони від прямої або хоча б одна точка чи лежить на прямій . Це значить, що
Нижче наведені різні випадки взаємного розташування двох відрізків і відповідні їм значення векторних добутків.
У наступному прикладі кожен з відрізків перетинає пряму, що містить інший відрізок. Однак обмежуючі їх прямокутники не перетинаються.
Приклад
У першому прикладі відрізки перетинаються. У другому прикладі — ні.
Реалізація алгоритму
Оскільки координати кінців відрізків є цілими числами, при обчисленнях ми будемо використовувати лише цілий тип long long. Надалі нам знадобиться функція sgn, яка визначає знак числа .
int sgn(long long n)
{
return (n > 0) - (n < 0);
}Функція RectanglesIntersects приймає як аргументи координати обмежуючих прямокутників для відрізків і . Вона повертає , якщо прямокутники (x_1, y_1) - (x_2, y_2) і (x_3, y_3) - (x_4, y_4) перетинаються, і в противному випадку.
int RectanglesIntersect(long long x1, long long y1,
long long x2, long long y2,
long long x3, long long y3,
long long x4, long long y4)
{
if (sgn(x3 - x2) * sgn(x4 - x1) > 0) return 0;
if (sgn(y3 - y2) * sgn(y4 - y1) > 0) return 0;
return 1;
}Функція cross обчислює векторний добуток двох векторів (A_x, A_y) і (B_x, B_y).
long long cross(long long Ax, long long Ay,
long long Bx, long long By)
{
return Ax * By - Ay * Bx;
}Функція intersect перевіряє, чи перетинаються відрізки і .
int segmentsIntersect(long long x1, long long y1,
long long x2, long long y2,
long long x3, long long y3,
long long x4, long long y4)
{Перевіряємо перетин обмежуючих прямокутників. Якщо вони не перетинаються, то повертаємо .
if (!RectanglesIntersect(
min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2),
min(x3, x4), min(y3, y4), max(x3, x4), max(y3, y4))
) return 0;Будуємо вектори AB, AC, AD.
long long ABx = x2 - x1, ABy = y2 - y1;
long long ACx = x3 - x1, ACy = y3 - y1;
long long ADx = x4 - x1, ADy = y4 - y1;Будуємо вектори CD, CA, CB.
long long CDx = x4 - x3, CDy = y4 - y3;
long long CAx = x1 - x3, CAy = y1 - y3;
long long CBx = x2 - x3, CBy = y2 - y3;Визначаємо векторні добутки.
long long ABxAC = cross(ABx, ABy, ACx, ACy); // AB x AC
long long ABxAD = cross(ABx, ABy, ADx, ADy); // AB x AD
long long CDxCA = cross(CDx, CDy, CAx, CAy); // CD x CA
long long CDxCB = cross(CDx, CDy, CBx, CBy); // CD x CBПеревіряємо пункти та критерію перетину відрізків. Якщо вони не виконуються, то повертаємо . Щоб уникнути переповнення, слід порівнювати з нулем не добуток чисел, а добуток їхніх знаків.
if (sgn(ABxAC) * sgn(ABxAD) > 0) return 0;
if (sgn(CDxCA) * sgn(CDxCB) > 0) return 0;
return 1; // Відрізки перетинаються
}Основна частина програми. Читаємо вхідні дані.
scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);
scanf("%lld %lld %lld %lld",&x3,&y3,&x4,&y4);Перевіряємо перетин відрізків.
if (segmentsIntersect(x1, y1, x2, y2, x3, y3, x4, y4))
puts("Так");
else
puts("Ні");