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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вам просто надо пересечь 3 окружности на плоскости. По "формула пересечения окружностей" гуглится, например, это или это.

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Алгоритм Ахо-Корасика.

    Все ваши ключи складываете в бор, как описано по ссылке. Потом для каждого кортежа выполняйте поиск в строке i[1], если нашли, то добавляйте ваш id в ответ.
    Ответ написан
    3 комментария
  • Как построить функцию декодирования классического кода Элиаса, если прямое кодирование работает правильно?

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

    И читайте это:
    1) подсчитайте сколько нулей идет в начале строки.
    2) Это сколько бит надо прочитать дальше и перевести в десятичную систему счисления.
    3) Это столько бит, сколько нужно прочитать дальше и перевести в десятичную систему, чтобы раскодировать число.
    Ответ написан
    Комментировать
  • Как сортировать массив с рандомными значениями?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    for(d=0; d < n; d++)
      x[i] = rand();
     printf("%d", x[i]);


    Цикл по d а присваивание в x[i]. Еще скобок нет, printf выполнится только один раз после цикла.

    Еще вы не выводите массив после сортировки, как вы вообще собираетесь понимать, что ваша программа работает?

    В самой сортировке (циклы по i и j), вроде, ошибок нет.
    Ответ написан
    Комментировать
  • Почему после очистки строки программа падает?

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

    Попробуйте после free присвоить msg_buf = NULL.
    Ответ написан
    Комментировать
  • Как найти количество перестановок числа?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это комбинаторика.

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

    Еще, в вашей формуле направшивается добавить пустое число ("") в ответ. Давайте разрешим его и вычтем в конце 1.

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

    Поэтому пусть f(a0,a1,...a9) - сколько есть способов расставить некторые из a0 нулей, a1 единиц, a2 двоек, и т.д. (ноль может идти в начале, число может быть пустым).

    Ответ к задаче f(a0,a1,...a9)-1-min(a0,1)*f(a0-1,a1,...a9). Последнее слагаемое считает варианты, начинающиеся с нуля. Оно не вычитается, если нулей в числе нет. -1 посередине вычитает пустое число из ответа (но ее нет в последнем слагаемом, ведь мы там еще 0 в начале приписываем и пустое число надо считать).

    Теперь самое интересное, формула для f(a0,a1,...a9). Замкнутой формулы я не нашел, но придумал, как считать алгоритмом.

    Можно все варинаты разделить по количеству символов в числе (n), от 0 до суммы a0...a9. Давайте подумаем, где могуть быть девятки? i <= a9 из них попадут в ответ. Они могут быть на C(n, i) позициях. Останется разместить остальные цифры на n-i позиций.

    Вырисовывается следующее динамическое программирование:

    F(i, n) - сколько способов разместить первые i цифр на n позициях (возможно, беря не все цифры).

    F(i,n) = sum (j=0..min(a[i-1], n)) F(i-1, n-j)*C(n, j)
    F(0, n>0) = 0
    F(i,0) = 1.
    Ответ - sum(k=0..a0+...+a9) F(9, k)

    У функции как бы неявный параметр массив a[] количеств всех цифр, но я его не включаю в параметры динамики, потому что по нему не надо мемоизировать.

    Не забудьте, что для подсчета второй динамики, для f(a0-1,...a9) надо будет полностью отчистить мемеоизацию, потому что массив a поменялся же.

    Этот алгоритм работает за O(9*n), где n - длина входного числа.

    Вот пример для входного числа 112: все цифры, которых в числе нет можно выкинуть из рассмотрения и работать с массивом a={2,1} (для всех десяти цифр слишком много писать).

    F(0,0) = 1
    F(0,1) = 0
    F(0,2) = 0
    F(0,3) = 0
    F(1, 0) = 1
    F(1,1) = F(0, 1)*C(1,0) + F(0,0)*C(1,1) = 1
    F(1,2) = F(0,2)*C(2, 0)+ F(0,1)*C(2,1) + F(0,0)*C(2,2) = 1
    F(1,3) = F(0,3)*C(3, 0)+ F(0,2)*C(3,1) + F(0,1)*C(3,2) = 0
    F(2,0) = 1
    F(2,1) = F(1,1)*C(1, 0) + F(1,0)*C(1,1) = 2
    F(2,2) = F(1,2)*C(2, 0) + F(1,1)*C(2,1) = 3
    F(2,3) = F(1,3)*C(3, 0) + F(1,2)*C(3,1) = 3

    Ответ F(2,3)+F(2,2)+F(2,1)+F(2,0) = 3+3+2+1= 9.

    Вычитаем 1 (пустое число) и получаем 8 чисел, как у вас в примере для 112.
    Ответ написан
    2 комментария
  • Почему одни, незначащие скобочки, меняют ответ?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас i - целое, а x - вещественное. При делении целого на целое идет деление нацело (с округлением вниз до целого). При делении целого на вещественное или вещественного на целое - результат вещественное.

    Если лишние скобки поставить, то у вас сначала происходит деление нацело (2*i+1)/(2*i), а потом домножение на вещественное.
    Без скобочек операции выполняются слева направо - a *(-1*x)*(2*i+1) даст вещественный результат, который точно поделится.

    Если вы в скобочках приведете к вещественному, то у вас тоже все заработает: a = a *(-1*x)*((2*i+1.0)/(2*i));
    Ответ написан
    Комментировать
  • Какие два числа до 60 наименее кратны друг другу в прогрессии?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Не очень понятно, но вам, похоже, нужны такие числа, чтобы у них был максимальное наименьшее общее кратное (это то самое 42 для 6 и 7).

    Из чисел до 60, очевидно, вам подходят числа 60 и 59 - у них нет общего делителя и НОК равен просто их произведению (3540). Если нужно строго меньше 60, то берите 58 и 59. Вообще, 2 максимальных числа в промежутке будут вашим ответом. У соседних чисел НОК всегда равен их произведению и произведение двух максимальных в отрезке будет самым большим возможным значением.
    Ответ написан
    1 комментарий
  • Как проверить, попадает ли географическая точка в правильный шестиугольник?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вычтите координаты центра из координат точки. Теперь шестиугольник лежит центром в (0, 0).

    Составьте 6 уравнений сторон шестиугольника в виде Ax+By+C=0, так что C положительно (если нет - домножте на -1). Подставьте в эти 6 уравнений координаты точки, все они должны дать положительные значения (или нули, если точка на границе считается лежащей внутри в вашей задаче).

    Почему это работает? Мы просто проверяем, что точка лежит с той же стороны от всех 6 прямых, что и центр (0, 0).

    Как составить уравнения? Найдите координаты 6-ти углов. Если сторона = a, то координаты точек (a, 0), (a/2, sqrt(3)*a/2), (-a/2, sqrt(3)*a/2), (-a, 0) ...

    Для уравнения одной из сторон возьмите в виде A разность по у у соседних точек, а в виде B разность по x (но с другим знаком). Потом подставьте туда координаты одной из точек и возьмите C так, чтобы был 0.

    Можно все 6 уравнений составить на бумажке и закодировать в программе.

    Пример для первой стороны:
    A = sqrt(3)*a/2-0 = sqrt(3)*a/2
    B = a - a/2 = a/2
    C = -A*a - B*0 = -sqrt(3)*a*a/2.

    Поскольку C отрицательно, меняем знаки:
    A = -sqrt(3)*a/2
    B = -a/2
    C = sqrt(3)*a*a/2

    Для второй прямой будет 0*x-a*y+sqrt(3)*a*a/2 = 0

    И да, это работает, если предположить, что шестиугольник маленький или на плоскости. если у вас кривизна земли играет роль, то все сильно усложняется.
    Ответ написан
  • Можете пожалуйста написать на С++ произведение сумм?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам надо перед циклами инициализировать переменные-аккамуляторы: Перед циклом по i нужно присвоить y = 1. Перед циклом по j нужно присвоить sum = 0.

    Иначе у вас в sum накапливается сумма для всех разных i. А y вообще непонятно какое значение имеет до домножения.
    Ответ написан
  • Python. Найти расстояние от точки до прямой, зная координаты этой точки?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Составьте уравнение прямой вида a*x+b*y+c=0.
    Подставьте в это уравнение координаты точки. Возьмите по модулю и поделите на sqrt(a^2+b^2).
    Ответ написан
    Комментировать
  • Как портировать линуксовое консольное приложение под Windows?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Можно попробовать какой-нибуть mingw поставить. Получается какбы линуксовая оболочка в винде. Можно компилить в ней исходники, получающийся exe-шник автоматом получит транслирование системных вызовов. Нет гарантии, что любой код заведется, но шансы есть.

    Т.е. виндовые исходники вы не получите, но есть вариант скомпилить эти линуксовые исходники в exe-шник, который, возможно, потребует установки mingw на машину, где приложение будет работать.

    Edit, возможно mingw тут не поможет и нужен cygwin. Еще был какой-то msys. Но я не уверен.

    На худой конец, под 10 виндой есть WSL.
    Ответ написан
    8 комментариев
  • Как быстро найти вершину,которая имеет наибольшее количество ребер и не соединена с данной вершиной?

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

    Но обычно вам и не надо решать эту задачу один раз для конкретной вершины. Как в приведенной задаче - вам надо решить ее для всех вершин графа одновременно. Кроме того, в приведенной задаче граф - всегда дерево.

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

    Но в этой задаче можно проще: Найдите все вершины с максимальной степенью. Если из 3 и более, то найдите среди них 2 не связанные (берете любую, потом еще одну любую. Если они связанны, то берите любую третью - она не связанна с одной из двух первых).

    Если их 2, то проверьте, вдруг они не связанны. Если же они соседние или такая всего одна, то найдите в графе еще одну вершину с максимальной степенью, которая не связанна хотя бы с одной из этих двух. Чтобы это работало за линию - заведите массив и прибавьте 1 ко всем соседям каждой из 1/2 максимальных вершин. Потом смотрите на те, где стоит 0 (или 1, если максимальных две).

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

    Почему это работает? Понятно, что в задаче надо найти пару не связанных вершин с максимальной суммой степеней. Очевидно, что в случае трех и более максимумов или двух несвязанных максимумов этот алгоритм даст самый оптимальный ответ - 2 наибольших числа в массиве. Лучше никак не сделать.

    Теперь рассмотрим случай двух связанных максимальных вершин. Рассмотрим оптимальный ответ. Если в нем нет одной из максимальных вершин, то мы могли бы заменить один из концов на максимум. Мы не можем этого сделать, только если оба конца связанны с обоими максимумами, а это означало бы циклы в графе. Но у нас же дерево! Значит, оптимальный ответ обязательно содержит одну из максимальных вершин. Но мы этот вариант в алгоритме перебрали.

    Остается случай из одной максимальной вершины. Опять же оптимальный ответ не содержит ее, только если его нельзя улучшить - а значит оба конца связанны с максимальной вершиной. Но этот случай мы тоже разобрали.
    Ответ написан
  • Сколько элементов массива больше своих соседей (предыдущего и следующего элементов)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Чтобы пропустить первый и последние элементы просто измените границы цикла:
    for (int i = 1; i < 24; i++)

    Если вы хотите эти элементы считать, если они больше единственного их соседа, то воспользуйтесь ленивым вычислением логических формул (при вычислении A || B, если A == true, то B вообще вычисляться не будет):
    for (int i = 0; i < 25; i++)
      {
        if ((i +1 == n || ARR[i] > ARR[i + 1]) && 
             (i == 0 || ARR[i] > ARR[i - 1]))
          count++;
      }
    Ответ написан
    1 комментарий
  • Правильно ли я понимаю запись через сигму?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Y у вас из множества R^W*H*2. Т.е. Y состоит из W*H*2 чисел проиндексированных тремя индексами - первый до w, второй до h, третий до 2. Соответственно в формуле считается сумма по всем значениям первых двух индексов. Y_wh - это пара чисел. У вас множества в примере неправильно составлены - там вместо a и b должны быть пары чисел.

    Далее, нижний индекс 2 после || - это обозначение нормы L2 в двумерном пространстве - это корень второй степени из суммы квадратов (обычное декартово расстояние). Верхний индекс после || - это просто возведение в квадрат, который отменяет извлечение корня для ||...||_2.

    Т.е. Вся эта формула говорит взять W*H*2 покомпонентные разности, возвести их в квадрат и сложить.
    Ответ написан
  • Почему основное тригонометрическое тождество работает всегда?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    > а почему тут работает ОТТ, если оно доказывается с помощью теоремы Пифагора?

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

    ОТТ применимо всегда! Для любых аргументов. Но, возможно вас именно это и запутало, после применения ОТТ и взятия корня, по идее, у вас получится +-sqrt(...). Потому что x^2=9 => x=3 или -3. Два варианта извлечения корня, 2 варианта для синуса.

    Но, поскольку вы знаете, что угол в треугольнике не может превышать 180 градусов, вы знаете, что синус этого угла всегда неотрицательный. Поэтому -sqrt() можно отбросить как лишнее значение и получить вашу формулу. В формальном доказательстве эти рассуждения надо учитывать.
    Ответ написан
    Комментировать
  • Как решить задачу по рекурсивным алгоритмом на python?

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам нужен цикл по строкам. Внутри считайте сумму каждой строки и выводите.
    Чтобы найти сумму одной строки вам нужен еще один цикл: Заводите переменную, равную 0, перед цикорм. В цикле прибавляете элементы строки к ней. Потом выводите.

    Таким образом, у вас будет 2 вложенных цикла.
    Ответ написан
    2 комментария
  • Как посчитать этот пример (суммы ряда)*(произведение ряда)+почему выводит такой результат?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    У вас ошибка в том, что вы считаете произведение один раз после цикла по k. На тот момент k после цикла равно n. Т.е. как будто у вас вместо k в формуле стоит n как граница для произведения.

    Вам надо считать proizr внутри цикла по k и домножать на него каждое слагаемое. (не забудьте инициализировать proizr единицей).
    Ответ написан
  • Как решить данную олимпиадную задачу?

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

    Во-первых, когда встает вопрос о можно-нельзя ли какими-то операциями получить что-то, первая мысль должна быть - придумать инвариант. Какое-то свойство, которое не меняется при применении операции. С опытом наберетесь идей для инвариантов. Тут сразу приходит в голову такой: Обозначим цвета цифрами от 0 до 2. Тогда при любом перекрашивании сумма всех чисел по модулю 3 не меняется. Если столбы одинаковые - сами числа не меняются, если 01 перекрасить в 22, 02 в 11 и 12 в 00, то сумма остается с таким же остатком от деления на 3.

    Отсюда можно сразу сделать вывод, что при N делящемся на 3 ответа нет. Потому что в конце мы должны получить все цвета одинаковые, а значит сумма будет 0, N или 2N - делится на N. Раз N делится на 3, то и итоговая сумма дает остаток 0 (по модулю 3). Но изначальная раскраска может иметь любой остаток (например, 00..0001). Значит решения для таких N нет.

    Далее, можно легко придумать, как "удваивать" решение. Пусть мы умеем получать какой-то N, то можно получить алгоритм для 2N. Сначала перекрашиваем первую половину по известному плану. Потом вторую половину. Потом попарно столбы из двух половин. Надеюсь, очевидно, почему это работает?

    Так можно получить ответ для 2,4,8,16, но этого мало.

    Следующая мысль, как можно построить универсальный план покраски - это воспользоваться тем, что если мы сделаем все столбы одинаковыми, то все последующие действия ничего не испортят. Т.е. можно взять конкретную раскраску столбов, составить план для нее. Потом взять следующий вариант входных данных, прогнать его через уже составленный план. Если результат не одноцветный - дополнить план так чтобы раскрасить все в один цвет и для этого варианта изначальной раскраски. Повторить со всеми возможными входными данными. Использовать эту идею для всех вариантов N раскрасок слишком медленно (их же 3^N). Вернемся к ней попозже.

    Следующая идея должна быть - раз для существования решения важно неделимость на 3, то возможно мы сможем к группе одинаковых столбов добавить 3 столба?

    После разбора нескольких случаев на бумаге я понял, что надо отдельно рассматривать случаи N%3=1 и N%3=2.

    Рассмотрим первый случай. У нас есть 3k столбов цвета А, и в конце еще 4 столба - AXYC (один из N и 3 новых). Задача - получить в конце 4 одинаковых цвета. У нас уже есть решение для N=4 в примере. Просто примените его к 4-м последним столбцам. Теперь у нас есть ...AAAZZZZ. Если A=Z, то все наши операции ничего не сделают. Рассмотрим только случай A!=Z. Красим A+Z, получаем AAYYZ..Z на конце Красим 2 раза A+Y. Т.е. за 3 операции мы перекрасили 3 последние A в Z. Повторяем операцию, пока все A не перекрасим (их же 3k, напоминаю).

    Теперь случай N=3k+2. У нас есть 3k A, и в конце AAXYC. Если у вас есть решение для 5, то получаете на конце 5 Z и аналогично предыдущему случаю перекрашиваете 3 последних A в цвет последних столбов.

    Т.е. отдельно рассматриваете случай разных остатков N%3. Потом решаете задачу для N=4 или 5 первых столбцов, потом добавляете по 3 столба: решаете задачу для 4/5 последних столбов и итеративно перекрашиваете по 3 столба из предыдущих.

    Это решение потребует максимум N/3*(F(5)+N) шагов, где F(5) - сколько нужно операций для решения N=5.

    Теперь решение для N=5. Тут и надо будет воспользоваться наблюдением о дополнении плана для разных входных данных. Вот есть 5 столбов. Покрасим 1+2 и 3+4. Теперь у нас есть AABBC. Возможно какие-то цвета одинаковые. Но сначала допустим, что они все три разные. Красим попарно A+B(1+3 и 2+4). Все. Но что, если B=C, B!=A? У нас было AABBB. Мы покрасили 1+3 и 2+4 - получили ССССA. Красим 4+5 - CCCBB. Теперь, как раньше, перекрасим 3С в B: 3+4 (CCAAB), 1+3(BCBAB), 2+4 (BBBBB).
    Теперь надо рассмотреть случай B=A, C!=A: AAAAC. Надо аккуратно повторить все операции выше - получим BBBBB. План для этого случая работает, ничего дописывать не надо. Остался случай A=C, C!=B. Т.е. дано AABBA. Применяем шаги выше и получим (перепроверьте!) AAAAA.

    Т.е весь план для N=5 1+2, 3+4, 1+3, 2+4, 4+5, 3+4, 1+3, 2+4.

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

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

    Возьмите максимальную степень двойки, помещающуюся в N. Пусть это k (2k > N, k <= N). Примените план для первых k. потом для последних k. Итого вы получите N-k столбов одного цвета и k столбов (возможно) другого цвета в конце. Если N-k делиться на 3 то, по известному плану "перекрашивания по тройкам" перекрасьте первые N-k в цвет последних k. Если же N-k не делиться на 3, то покрасьте попарно столбы цвета первых N-k и цвета вторых N-k. Потом останутся какие-то столбы в конце другого цвета, но их количество точно будет делиться на 3 (доказательство этого факта придумайте сами. Рассмотрите какие могут быть остатки от деления на 3 у k и N-k). Раз у нас группа другого цвета состоящая из троек, то мы умеем ее перекрашивать.

    Этот вариант будет требовать не квадратичное, а O(n log n) количество операций.
    Ответ написан
    Комментировать