Ответы пользователя по тегу Геометрия
  • Задача на геометрию. Как быстро найти подходящую выборку элементов из матрицы?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Чтобы расставить жуков оптимально, надо бинпоиском перебрать максимально разрешенное растояние и дальше проверить, что в графе из расстояний, не больше заданного, есть полное паросочетание.

    Еще, угол поворота надо искать троичным поиском, ибо функция не монотонна, а пооизводную фиг найдете. В итоге у вас будет троичный поиск, запускающий двоичный поиск, щапускающий поиск паросочетания.
    Ответ написан
  • Если мы возьмём кубическую кривую Безье и вытянем усы в одну точку, будет ли это квадратичная кривая?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Нет. Потому что кривая называется "кубической" не потому, что там 4 разные точки, а потому что она задается уравнением третьей степени (кубы): a(1-t)^3+bt(1-t)^2+ct^2(1-t)+dt^3. Если вы приравняете b и c, то уравнение так и останется кубическим и в квадртаичное не превратится.
    Ответ написан
  • Что значит описать встретившуюся геометрическую фигуру и определить положение точки в этой фигуре?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Кажется, надо составить уравнение/функцию, которая говорит, что точка попала в данную фигуру. Фигуры, скорее всего, задаются цветом.
    Ответ написан
    Комментировать
  • Что такое х0, что такое у0, что такое х?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    x, y - переменные. Они изображаются на графике. x0, y0, a - какие-то фиксированные параметры прямой, числа. Точка, через которую она проходит и наклон.

    Синяя линяя, наверно, прямая, описываемая этим уравнением.
    Ответ написан
    Комментировать
  • Как получить точку касания вектора, зная его начало и модуль?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Одно квадратное уравнение. Пусть точка конца имеет координаты t*v3. Уранение: |t*v3-v1|^2=100^2 (расстояние от начала до конца - 100). Распишите длину как сумму квадратов разностей по всем координатам. Там квадратное уравнение на t, ведь координаты v1 и v3 даны. Найдите положительный корень.
    Ответ написан
  • Формула вращающегося прямоугольника как?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Ну это же школьная геометрия. (L-W)/sqrt(2), если длинная сторона L, а короткая W.

    Там равносторонний прямоугольный треугольник с длиной (L-W)/2 (вычли пересечение из длины, осталось 2 одинаковых куска, поделили пополам - нашли искомый кусок. А дальше - теорема Пифагора.
    Ответ написан
  • Почему базисом для плоскости в трёхмерном пространстве является Null Space?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Плоскость проходит через ноль. Значит вектор-базис в этой плоскости тоже удовлетворяет уравнению (ведь любой вектор в плоскости имеет координаты точки конца - а она на плоскости).

    Ваша матрица с нулями при умножении как раз вычисляет уравнение. А раз вектор удовлетворяет уравнению, то получится 0.
    Ответ написан
    Комментировать
  • Возможен ли треугольник по стороне, углу и пропорциональным сторонам?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Треугольник можно составить из любых трех отрезков, пока выпонляется неравенство труегольника a+b > c, a+c > b, b+c > a. достаточно проверять только одно из них - максимальное число должно быть меньше суммы остальных. Но если не очевидно, какое из них максимальное, то можно проверять все три.

    Итак, дано только A и k, так?

    Чтобы как-то угол связать со сторонами надо воспользоваться теоремой косинусов:

    c^2 = a^2+b^2-2*a*b*cosA.
    подставив суда b=ck, получим
    с^2 = a^2+k^2c^2-2*k*a*c*cosA

    Это квадратное уравнение, связывающее C и A. Можно решить его относительно a (c - параметр) и вы получите а, выраженное через с.

    Ну и в конце надо проверить, что a+b > c, a+c > b, b+c > a, подставив туда найденные формулы для b и a через c. В этих неравенствах будут известные cosA, sinA, k и неизвестная с. Поскольку тругольник по углу и соотношению сторон можно масшабировать, то неравнество должно выполнятся для всех c. Но на самом деле в этих неравенствах все c можно будет тупо сократить. Какие-то из них можно сразу же выкинуть, если рассмотреть 2 случая k>1 и k<=1. Ну а как их дальше решать - думайте сами.
    Ответ написан
    3 комментария
  • Как найти треугольники с максимальной площадью?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    До 15 точек можно полным перебором сделать. Вам надо перебрать все разбиения 3n точек на тройки. Таких разбиений (3n)!/(3!)^n/n! для n=5 - это чуть больше миллиона.

    Вы у себя перебираете все треугольники, даже если они имеют общие точки, это сильно раздувает количество вариантов.

    Перебирать можно рекурсивно - берите первую точку без треугольника и пребирайте 2 оставшиеся, которые будут образовывать с ней треугольник. Помечайте их в треугольник и рекурсивно запускайтесь дальше. Потом откатывайте последние изменения и перебирайте другие варианты. Дальше надо проверить, что никакие 2 теругольника не пересекаются и не лежат друг в друге. Если это еще и делать по мере генерации, то можно неплохо ускорить решение за счет отсечения заведомо невозможных ваниантов. Может даже до 21 одной точки будет работать терпимо по скорости.

    Какое-то геометрическое решение в голову что-то не приходит.
    Ответ написан
    Комментировать
  • Как определить направление рисования дуги?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Воспользуйтесь векторным произведением векторов из центра окружности на две точки. Оно вам даст положительное значение, если от первого ко второму вектору надо идти против часовой стрелки и отрицательное - наоборот. Ноль, если вектора лежат на одной прямой с центром окружности.

    Форомула будет (x0 - xr)(y1-yr) - (x1-xr)(y0-yr), где xr, yr - центр окружности.
    Ответ написан
    Комментировать
  • Как равномерно разместить N юнитов на окружности?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В полярной системе координат их позиции вычислить элементарно: у i-того солдата угол 2pi*i/n и радус фиксированный.

    Для перехода из полярной системы координат в обычную воспользуйтесь тригонометрическими функциями:
    x_i = x_o+cos(alpha_i)*r_i
    y_i = y_o+sin(alpha_i)*r_i
    Ответ написан
    1 комментарий
  • Требуется минимизировать количество точек с хотя бы одной целочисленной координатой на линии. Как это сделать?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Представьте сетку вдоль целых координат. Ваши две точки в каких-то ячейках. Чтобы перейти из одной ячейки в соседнюю придется пересечь границу - это будет считаемая точка.

    Т.е. вам надо найти путь из одной клетки в другую, пройдя по как можно меньшему количеству клеток. Можно ходить в 8 направлений - если пересечь угол, то можно за одну точку на ломаной перейти по диагонали.

    Немного порисовав вы поймёте, что ответ - миксимум из горизонтального и вертикального расстояний между начальной и конечной клетками.

    Надо только аккуратно разобрать случаи, если начальная или конечная точка лежит на границе клетки.
    Ответ написан
    1 комментарий
  • Как найти координаты вершин треугольника вписанного в другой треугольник?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Есть много способов. Мне нравится векторный. Для каждой вершины отложите вектор длины x вдоль стороны против часовой стрелки. Потом отложите вектор длины l, перпендикулярный внутрь.

    Длину x можно найти, если посмотреть на картинку hint000 - это длина катета. При чем вам дан второй катет (l). Значит надо поделить или умножить на тангенс угла, который есть половина угла в вершине.

    Вот когда вы нашли длину x, чтобы получить вектор вдоль стороны просто вычтите координаты одной вершины из другой. поделите его на его же длину. Потом домножте на x. Чтобы получить перпендикулярный вектор вам надо просто поменять местами координаты и обратить знак у одной. Где именно ставить минус можно понять, если посмотреть на картинку.

    Тут вам понадобится найти углы у нижних вершин треугольника, но это школьная задача - углы равны, их сумма плюс известный верхний дадут pi/2.
    Ответ написан
    Комментировать
  • Как проверить, принадлежит ли точка на плоскости указанной части окружности?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Во-первых, проверьте, что точка лежит внутри окружности (просто сравните расстояние до A).

    Во-вторых, надо проверить, что точка лежит в секторе. Тут есть 2 варианта. Можно получить углы границ и направления на точку через арктангенс и сравнить, но там много частных случаев, особенно при переходе через 0. Альтернативный вариант - использовать вектора. Пусть искомая точка - P. Тогда вам надо проверить, что вектор AP дает с вектором AB угол меньше y. Можно найти косинус угла через скалярное произведение и потом сравнить его с косинусом y.

    Вам надо, чтобы (AB,AP)/(|AB|*|AP|) >= cos y
    Ответ написан
    Комментировать
  • Как узнать, пересекутся векторы?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Введите 2 переменные t и q - это "время" на первом и втором луче, составьте 2 уравнения. Решите их - найдете время пересечения на каждом луче. Убедитесь, что пересечения при t>=0, q>=0:
    x1+t*vx1=x2+q*vx2
    y1+t*vy1=y2+q*vy2


    надо проверить, что оно имеет решение. Преобразуйте его к стандартному виду:
    t*vx1-q*vx2=x2-x1
    t*vy1-q*vy2=y2-y1


    Решите систему методом Краммера. Если определитель системы != 0 - то найдте 2 переменные q и t. Проверьте, что они обе неотрицательные.

    Если определитель равен нулю, то прямые или не пересекаются вообще, или совпадают. Они совпадают, если оба вспомогательные определители системы равны 0.

    В этом случае надо проверить, что лучи пересекаются по отрезку или лучу. Для этого надо проверить, а не лежит ли начало второго луча на первом и наоборот. Для этой проверки можно воспользоватся векторным произведением векторов. Считаете вектор {x2-x1, y2-y1} и умножаете на вектор {vx1, vy1}. Эти 2 вектора или смотрят в одну сторону (и пересечение есть), или в разные. В первом случае векторное произведение будет положительно, во втором - отрицательно. Нулевое произведение считайте как положительное - это значит что или точки совпадают или вектор направления нулевой.

    Т.е. весь алгоритм
    1) Считайте 3 определителя по методу краммера
    2) Если главный определитель не 0, считайте q и t. Пересечение есть, если q>=0 и t>=0.
    3) Если главный определитель 0, но хотя бы один из вспомогательных не 0 - пересечения нет.
    4) Считайте векторное произведение {x2-x1, y2-y1} на {vx1, vy1}. Если оно неотрицательно - пересечение есть.
    5) Считайте векторное произведение {x1-x2, y1-y2} на {vx2, vy2}. Если оно неотрицательно - пересечение есть.
    Ответ написан
    1 комментарий
  • Как вывести полярное уравнение эллипса, гиперболы, параболы?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Берете уравнение вашей функции в виде F(x,y)=0. Подставляете туда x=x0+r*cos(fi), y=y0+r*sin(fi). Выражаете r через fi - вот и уравнение в полярных координатах.

    Тут будет много формул. Во-первых, уравнение F(x,y)=0 надо составить через через эксинцесинтрет и фокальный параметр. Координаты фокуса тоже надо через них выразить. Во-вторых выражение с косинусами и синусами придется хорошенько причесать используя всякие тригонометрические тождества.
    Ответ написан
    Комментировать
  • Как отобразить плоскость на сфере?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Это очень спорная тема. Без каких-то искажений вы проекцию никогда не получите. Сфера и плоскость обладают несовместимыми топологическими характеристиками.

    Один вариант, сохраняющий углы, но не сохраняющий пропорции - проекция меркатора. Фактически, это циллиндрическая проекция: https://en.wikipedia.org/wiki/Map_projection#Cylin...

    Сначла спроецируйте параметризуйте вашу карту, выделив в ней прямоугольную карту мира. Потом спроецируйте этот прямоугольник на цилиндр вокруг сферы. И потом уже спроецируйте каждую точку цилиндра на сферу.
    Ответ написан
    Комментировать
  • Как выглядит стандартное решение эллипса по центру и 3 точкам?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    TL;DR:
    S = Pi*sqrt(3 / [ (1/L1+1/L2+1/L3)^2-2*(1/L1^2+1/L2^2+1/L3^2) ])

    тут L1, L2, L3 - квадраты трех измерений.

    Вывод формул:
    Чуть-чуть аналитической геометрии и куча элементарной алгебры помогут вам вывести эти уравнения.
    Если ввести систему координат с осями по главным радиусам эллипса, то уравнение эллипса будет:
    x^2/a^2+y^2/b^2 = 1

    При этом все точки под углом alpha к большой полуоси будут на луче:
    x(t, alpha) = t*cos(alpha)
    y(t, alpha) = t*sin(alpha)


    Обозначим синус и косинус угла для первого измерения как:
    s = sin(a1), c = cos(a1)

    Пусть квадраты расстояний - L1, L2, L3.

    Если пересечь луч и эллипс, то можно составить уравнение для длины вдоль угла a1 (первое измерение), просто подставив известные x(a1, sqrt(L1)) и y(a1, sqrt(L1)).
    1/L1 = c^2/a^2+s^2/b^2

    Для остальных измерений надо прибавлять 120 градусов к углу под cos и sin. Если раскрыть cos(120+a1) = cos(120)cos(a1)-sin(120)sin(a1) и sin(120+a1) = cos(120)sin(a1)+sin(120)cos(a1), то можно составить еще 2 уравнения:

    1/L2 = (-1/2*c-sqrt(3)/2*s)^2/a^2+(sqrt(3)/2*c-1/2*s)^2/b^2
    L3 = (-1/2*c+sqrt(3)/2*s)^2/a^2+(-sqrt(3)/2*c-1/2*s)^2/b^2


    Всего с учетом тригонометрического тождества s^2+c^2=1 у нас 4 уравнения на 4 неизвестных a, b, c, s.

    Но нам не нужны все значения. Площадь эллипса Pi*a*b, а радиусы эллипса - a и b.

    Раскрыв квадраты выше и всячески складывая эти уравнения можно получить в итоге
    1/a^2+1/b^2 = 2/3*(1/L1+1/L2+1/L3)
    1/a^2*b^2 = [ (1/L1+1/L2+1/L3)^2-2*(1/L1^2+1/L2^2+1/L3^2) ]/3


    Отсюда площадь:
    S = Pi*ab = Pi*sqrt([ (L1+L2+L3)^2-2*(L1^2+L2^2+L3^2 ]/3)


    Чтобы найти радиусы эллипса, вам надо найти a и b. Выше уже даны два уравнения для суммы и произведения 1/a^2 и 1/b^2 - можно из них получить квадратное уравнение для t=1/a^2. Два его решения и будут вашими радиусами эллипса (не забудьте взять корни и обратить). Тут надо аккуратно подставить выражения в школьные формулы для квадратного уравнения.
    Ответ написан
    9 комментариев
  • Как грамотно остановить объект при столкновении?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Во-первых, если скорости маленькие и движение происходит на маленькие отрезки за итерацию, то можно выталкивать объект в любую сторону.

    Если же шаги не настолько мелкие, то нужно, как уже подсказал Фокс Йовович, сдвигать до пересечения, а не впихивать объект в другой и выталкивать назад.

    Есть концептуально простой но далеко не самый эффективный метод - бинарный поиск. Вот вы уже умеете определять, пересекаются ли 2 объекта. Изначально они не пересекались, после сдвигания на 1.0 едениц веремени они пересеклись. Делайте бинарный поиск по времени в отрезке (0, 1): посморите, есть ли пересечение при сдвиге на 0.5 единиц времени. Потом или 0.25 или 0.75 в зависимости от результата проверки. И так пока текущий отрезко в бинпоиске не станет достаточно мал. Но у этого метода большая проблема с большими скоростями - если за время итерации объекты пройдут сквозь друг друга - вы этого не заметите.

    Более быстрый метод - это реально искать пересечение тракетории. Для этого пустите лучи из каждой вершины одного объекта параллельные его скорости движения относительно второго объекта. Потом пересеките каждый луч со вторым многоугольником и найдите кратчайший луч. Аналогично надо пустить лучи из всех вершин второго многоугольника в обратную сторону и пересечь их все с первым многоугольником (это если движущийся наткнется на вершину препятствия стороной). Нашли длину минимального луча - на нее и сдвигайтесь. Если задавать лучи параметрически в виде point+t*v, то фактически вы ищете минимальное значение параметра t при пересечении у всех лучей (тут v - вектор скорости за один квант времени,point - вектор координат точки, из который выпустили луч).

    В этом методе не надо даже проверять, попадает ли после полного шага объект в препятствие. Нашли минимальное расстояние до пересечения (может быть и бесконечностью, если пересечений нет) - если оно больше сдвига за квант времени, то сдвигайтесь просто на квант времени. в параметрическом подходе, это значит, что сдвигаетесь вы на min(1.0, t).

    Этот метод можно соптимизировать с квадратичного до линейного. Представьте, что вектор движения горизонтален (и направлен влево). Можно просто повернуть все точки каждого многоугольника вместе со всем пространством или применять векторные/скалярные произведения для определения, какая точка ниже/левее/правее.

    Найдите в каждом многоугольнике самую нижнюю и самую верхнюю точку. Если эти промежутки по OY не пересекаются - то два объекта не столкнутся, можно останавливать проверки. Если промежутки по OY пересекаются, но второй обхект находится правее первого - то они отдаляются и опять можно дальше не проверять. Тут можно сравнить по одной любой точке с каждого объекта.

    Потом, как в алгоритме слияния двух отсортированных массивов, берете 2 указателя на 2 самые нижние точки в объектах. В левом объекте указатель будет двигаться против часовой стрелки, а в правом - по. Так вы будете обходить лицевые стороны объектов. Смотрите, какая из двух точек ниже. Пускаете луч из нее и пересекаете с одним отрезком - выходящим из текущей точки на втором многоугольнике вверх, и только с ним. Сдвигаете указатель с той самой нижней точки на следующую. Отстанавливаетесь, когда дошли до обеих высших точек.

    Этот метод быстрее, потому что не надо проверять пересечения со всеми отрезками многоугольника у луча, а только с одним.

    Можно его до сублинейного соптимизировать через бинарный поиск опять, но тут уже очень сложно. Можно низшую и высшую точки искать за логарифм бинпоиском, а не как выше полным перебором всех точек. Потом тернарным поиском перебираете значение координаты Y и считаете расстояние между двумя многоугольниками вдоль этого горизонтального отрезка. Для этого, опять же бинпоиском, находите 2 отрезка пересекающих эту горизонталь в обоих многоуголниках и пересекаете с горизонталью, чтобы найти 2 конца расстояния. Эта функция расстояния dist(y) будет выпуклой. Поэтому уможно найти ее минимум тернарным поиском.
    Ответ написан
    2 комментария
  • Как построить симуляцию луча?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Как это часто бывает в задачах на отражение света, не надо отражать луч. Представьте, что зеркало - это портал в Зазеркалье. Луч идет прямо и, проходя через зеркало, попадает в соседнюю треугольную комнату.

    В этой задаче нужно представить, что вся плоскость замощена треугольниками, прямой луч выходит из одной точки до другой. Сколько сторон треугольников он пересечет - столько отрвжений и сделано.

    Отражения, если вам так хочется, можно делать через вектора. Есть у вас вектор вдоль луча, и вектор вдоль зеркала и нормаль внутрь. Через скалярное произведение можно разложить вектор луча на перпендикуляр и паралледьный к зеркалу. Потом надо развернуть вектор перпендикуляр и сложить их.

    Но в этой задаче это вам не поможет никак - ибо симулировать эти 100500 отражений и квантилионы возможных начальных углов никакого времени не хватит.
    Ответ написан
    2 комментария