Условие
Капля дождя падает вертикально вниз с большой высоты на землю. На пути у капли могут встретиться препятствия, которые изменяют ее путь к земле.
Напишите программу, которая по координате $\ x_0\ $ точки появления капли над землей вычисляет координату $x$ точки соприкосновения капли с землей $\ \left(y = 0\right).\ $ Будем рассматривать двумерный вариант (на плоскости) этой задачи. Пусть препятствия – это наклонные непересекающиеся отрезки, а капля имеет точечные размеры. Капля падает вертикально вниз из точки, расположенной выше любого из препятствий. Если капля при падении соприкасается с отрезком-препятствием, то она стекает по отрезку вниз, пока не упадет вертикально вниз с меньшего по высоте конца отрезка.
Входные данные
Во входном файле в первой строке содержатся два целых числа через пробел – координата $\ x_0\ $ точки появления капли $\ \left( 0 \lt x_0 \lt 10000\right)\ $ и количество отрезков-препятствий $\ N\ (0 \leqslant N \leqslant 100).\ $ Далее следует $\ N\ $ строк, каждая из которых содержит четыре разделенные пробелами числа $\ x_1,\ $ $\ y_1,\ $ $\ x_2,\ $ $\ y_2\ $ – координаты левого и правого концов отрезка-препятствия (все числа целые и находятся в диапазоне от $\ 0$\ до $\ 10000\ $, $\ x_1 \lt x_2,$ $y_1 \neq y_2.\ $ Отрезки не пересекаются и не соприкасаются.
Выходные данные
В выходной файл вывести одно целое число – координату $\ x\ $ точки соприкосновения капли с землей.
Тесты
Входные данные Выходные данные
30 4 25 35 40 30 1 32 20 30 33 22 50 29 18 10 33 19 |
18 |
7 5 1 6 10 8 5 3 8 2 6 10 11 9 9 10 14 12 6 6 12 7 |
8 |
4 4 1 1 3 3 2 3 0 6 7 3 5 2 6 5 9 6 |
4 |
8 3 8 6 2 4 7 4 9 3 6 1 10 2 |
2 |
2 3 5 9998 0 10000 7 9996 11 9994 4 9996 9 9993 |
9 |
Код программы
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <iostream> #include <cmath> #include <vector> #define MAX_Y 10000; using namespace std; struct slide { double x1; double y1; double x2; double y2; }; //высота соприкосновения капли с крышей [ур-ние прямой по 2-м точкам] double f (slide x, double x0) { double dx = x.x2 - x.x1; double dy = x.y2 - x.y1; return ((dy*(x0 - x.x1))/dx + x.y1); } vector <slide> roof; //вектор всех крыш //считывание и заполнение данных void read (int n) { while (n--) { double a, b, c, d; slide x; cin >> a >> b >> c >> d; if (a < c) { x.x1 = a; x.y1 = b; x.x2 = c; x.y2 = d; } else { x.x1 = c; x.y1 = d; x.x2 = a; x.y2 = b; } roof.push_back(x); } } int main() { int n, x, y = MAX_Y + 1; slide a; cin >> x >> n; if (n == 0) { cout << x; return 0; } read (n); while (roof.size()) { int index = -1; int value = -1; //предполагаемая высока соприкосновения капли со следующей крышей bool no_projection = true; for (int i = 0; i < roof.size(); i++) { //поиск самой высокой крыши в точке х if ((x <= roof[i].x2) and (x >= roof[i].x1)) { //капля проектируется на и-тую крышу? no_projection = false; if ((f(roof[i], x) > value) and (f(roof[i], x) < y)) { //и-тая крыша выше ранее найденной? value = f(roof[i], x); index = i; } } if (min(roof[i].y1, roof[i].y2) > y) { //крыша целиком осталась выше? roof.erase(roof.begin() + i); i--; } } if ((roof.size() == 0) or (no_projection)) { //если удалили все крыши или свободно падает на землю cout << x; return 0; } if (roof[index].y1 < roof[index].y2) //какой конец крыши ниже? x = roof[index].x1; else x = roof[index].x2; y = min(roof[index].y1, roof[index].y2); //сохранили новую ординату roof.erase(roof.begin() + index); } cout << x; return 0; } |
Решение
Для удобства создадим структуру slide, которая будет описывать координаты концов отрезка-крыши. Также будем считать, что первый конец отрезка находится левее (для этого будем менять местами точки в случае необходимости).
Будем представлять каждую крышу как отрезок прямой на плоскости. Для этого применим уравнение прямой по двум точкам, принадлежащим этой прямой:
$$\frac{x — x_1}{x_2 — x1}=\frac{y — y_1}{y_2 — y_1}$$
Чтобы проверить, может ли капля в текущий момент проектироваться на некоторую крышу, надо проверить, находится ли абсцисса капли между абсциссами концов отрезка-крыши, а также найти ту крышу, которая в абсциссе капли «выше всех» (другими словами, у какой из прямых, которым принадлежат те отрезки, на которые проектируется капля, наибольшее значение ординаты в абсциссе капли). Для этого создадим функцию, которая и будет возвращать искомое значение ординаты. Также важно убедиться в том, что эта крыша находится ниже текущего положения капли. Заметим, что если некоторая крыша целиком находится выше капли, то мы на неё уже никогда не попадем, поэтому её нужно удалить из вектора. Найдя нужную крышу, определим новые координаты капли после того, как она скатится по этой крыше. Если капля в свободном падении и на её пути больше нет препятствий (крыш не осталось или нет такой, на которую проектируется капля), то текущая абсцисса капли и будет ответом на задачу.
Ссылки
Условие задачи на eolymp.com
Решение задачи на ideone.com