Задать вопрос
Ответы пользователя по тегу Алгоритмы
  • Какой хэшкод является идейно верным?

    @Mercury13
    Программист на «си с крестами» и не только
    Существуют так называемые криптографические хэши, задача которых — сделать, чтобы генерация двух документов с одинаковым хэшем была вычислительно невозможна. Если хэш удлиняется на два бита, эта задача усложняется, насколько мне известно, не вчетверо, а вдвое.

    Потому криптографические хэши огромные (устаревший MD5 — 16 байтов, большинство современных — 32 или 64). Как его записать в БД, если и тип такой не всегда есть, а BLOB’ы — пальба из пушки по муравьям? Как-то закодировать в строчку. К тому же в вебе есть места, где двоичные данные не катят и без строчного кодирования никак (например, URL’ы).

    Автор, очевидно, мэн из лагеря Perl/PHP и в дополнение к вычислению хэша взял и закодировал его. Вероятно, методом BASE64 (8 символов BASE64 соответствуют 6-байтовому хэшу). Для чего так кодировать обычные, не криптографические хэши — я вообще не знаю!
    Ответ написан
    Комментировать
  • Как найти алгоритм?

    @Mercury13
    Программист на «си с крестами» и не только
    Если число 3 задано жёстко, проще всего тройной цикл
    для i = [0..n—2)
      для j = [i+1..n−1)
        для k = [j+1..n)


    Если нежёстко, то получаем такое.

    Изначально массив инициализирован числами 0, 1, 2. Шагом является вот такая сложная операция.
    Добавляем единицу к последнему элементу. Если он больше n−1, то крутим вторую итерацию цикла — добавляем 1 к предпоследнему, если он больше n−2, крутим третью.
    Если цикл прошёл весь массив и так и не закончился — перебор окончен. Иначе идём по массиву вперёд и заполняем хвост числами a[i]+1, a[i]+2…
    Ответ написан
    3 комментария
  • Как задать паролем перемешивание 32 элементов?

    @Mercury13
    Программист на «си с крестами» и не только
    Если не нужна криптостойкость, то…
    1. Преобразовать (однозначно) в очень длинное число.
    2. Получаем такие части этого числа.
    • Остаток от деления на 32
    • Неполное частное на 32, затем остаток на 31
    • Неполное частное на 32·31, затем остаток на 30
    • Неполное частное на 32·31·30, затем остаток на 29…
    На словах страшно, алгоритм простейший.
    3. Из 31 числа — первое от 0 до 31, второе от 0 до 30, последнее 0 или 1 — легко получить перестановку.

    Если криптостойкость всё же нужна — придётся пароль «посолить» до достаточной длины и зашифровать чем-то.
    Ответ написан
    1 комментарий
  • Как перевернуть строку за пол прохода цикла?

    @Mercury13
    Программист на «си с крестами» и не только
    Первую букву меняем с последней, вторую с предпоследней, и так далее.
    Ответ написан
    Комментировать
  • Как найти наиболее вероятные пути прохождения ориентированного графа?

    @Mercury13
    Программист на «си с крестами» и не только
    Замкнуть выход на вход. Каждой вершине придумать вероятности (да хоть 1/n).
    Получаем цепь Маркова, остаётся найти её эргодическое распределение.
    Надо только придумать разглючку на случай, если ЦМ будет периодической — но, возможно, стандартные методы регуляризации СЛАУ с этим справятся.
    Ответ написан
    Комментировать
  • Как понять решение задачи по нахождению всех анаграмм (рекурсия)?

    @Mercury13
    Программист на «си с крестами» и не только
    По очереди для каждого из элементов.
    1. Поставить его на последнее место.
    2. Вызвать функцию рекурсивно с длиной на 1 меньшей.

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

    @Mercury13
    Программист на «си с крестами» и не только
    В общем случае да. Но иногда подобные оценки можно упростить. И упрощения можно делать по двум статьям:
    1. Более точные оценки. В данном случае не могу придумать.
    2. Более простые оценки: ведь оценка — это символ Ландау O(f(·)), который с точностью до константы. Если, например, K<N, а L<M, то сложность будет просто N·M.
    Ответ написан
    Комментировать
  • Как нарисовать дерево имея его ребра?

    @Mercury13
    Программист на «си с крестами» и не только
    Простите, что запоздало вклиниваюсь.
    Я как-то отвечал насчёт того, как сделать непересекающееся дерево.
    Как построить произвольное дерево?
    Ответ написан
    1 комментарий
  • Как узнать время выполнения сортировки в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Используйте либо time.h из Си, либо std::chrono из Си++11. Вот пример по второму.
    #include <iostream>
    #include <chrono>
    
    int main()
    {
        using Time = std::chrono::time_point<std::chrono::high_resolution_clock>;
        using Diff = std::chrono::milliseconds;
    
        Time t1 = std::chrono::high_resolution_clock::now();
        int i;
        std::cin >> i;
        Time t2 = std::chrono::high_resolution_clock::now();
        Diff diff = std::chrono::duration_cast<Diff>(t2 - t1);
        std::cout << diff.count() << " ms" << std::endl;
        return 0;
    }
    Ответ написан
    Комментировать
  • Объединение пересекающихся периодов?

    @Mercury13
    Программист на «си с крестами» и не только
    отсортировать массив по start
    текКонец := −∞   // или, например, ⌀ или 0000-01-01
    текИндекс := −1
    для v : массив
      если v.start > текКонец
        текИндекс += 1
      результат[текИндекс].приклеить(v)
      текКонец := макс(текКонец, v.end)


    Если же нужно объединять прямо на ходу…
    отсортировать массив по start
    текКонец := −∞   // или, например, ⌀ или 0000-01-01
    текИндекс := −1
    для v : массив
      если v.start > текКонец
        текИндекс += 1
        результат[текИндекс] := v
      иначе
        результат[текИндекс] := объединить(результат[текИндекс], v)
      текКонец := макс(текКонец, v.end)


    Разумеется, я тут опустил вопросы, связанные с датами-строками и их сравнением. Но вам их придётся решить.
    Изначально считается, что везде end > start. Если не так — данные некорректные и с этим придётся что-то делать.
    Также считается, что массив «результат» ассоциативный (как в PHP).
    Ответ написан
  • Как решить данную задачу?

    @Mercury13
    Программист на «си с крестами» и не только
    Задача сложна и требует серьёзного исследования. Дело тут в том, что второй эшелон — склад промежуточного хранения — добавляют, если затраты НЕлинейны и в больших объёмах развоз товара дешевле. Это, конечно, можно сымитировать более дешёвым завозом на склады. (А также чтобы разгрузить «мёртвые запасы» магазинов и законом больших чисел скомпенсировать случайные колебания спроса, но это, как я понял, не ваше дело.)

    У вас написано: «Стоимость доставки это расстояния между точками». Таким образом, стоимость доставки не зависит от объёма подвоза, а зависит только от расстояния? Тоже, так сказать, нелинейное поведение. Приближённое решение ищите в алгоритмах кластеризации: зона, охватываемая одним складом — и есть кластер. Если же нужно точнее, приходится использовать какие-нибудь эвристики.

    Например, расположим семь складов в каких-нибудь городах, вычислим вытекающую стоимость. А теперь вопрос: можно ли перенести какой-нибудь склад в соседний город, чтобы было дешевле? Итерационно работаем, пока не уляжемся в «оптимальное положение». Случайно набрасываем семь точек — и «скатываемся вниз», пока не успокоимся, и так много-много раз.

    Лучше выводить не одно решение, а несколько — например, до 120% от оптимального. Дело в том, что после компьютерного вычисления возникнут какие-то человеческие факторы: узнав, что восточный склад только в Комсомольске-на-Амуре, а северо-западный можно ставить где угодно в окрестностях Ленинграда, принимаем решение ставить склады в Комсомольске и недалеко от ленинградского метро.
    Ответ написан
    Комментировать
  • Как реализовать приближенный двоичный поиск?

    @Mercury13
    Программист на «си с крестами» и не только
    Алгоритм такой.
    1. Реализуй двоичный поиск с указанием места, куда вставить (см. Википедию).
    2. Если вставить до первой позиции или за последнюю — return соотв. первое или последнее число.
    3. В противном случае выяснить, какое ближе из (i−1)-го и i-го.

    Дома проверю, где там ошибка в двоичном поиске, в нём любят ошибаться.

    К тому же код у вас чисто олимпиадный, я бы отделил рабочую логику от генерации выходного файла.
    Ответ написан
  • Как найти среднее Hue (или другую «закольцованную» величину)?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Пока самый удачный способ таков.

    Переходим в координаты (x, y): x = cos(hue) · sat, y = sin(hue) · sat.
    Там можно получить среднее (x, y) и взять atan2.
    Ответ написан
    Комментировать
  • Как быстро проверить правильная ли скобочная последовательность?

    @Mercury13
    Программист на «си с крестами» и не только
    Критерий таков.
    1. Баланс ( и ) должен сохраниться.
    2. а) Либо вырожденный случай (скобку меняем дважды на противоположную);
    б) либо ) → ( идёт перед ( → );
    в) либо уровень вложенности обеих скобок не менее 3, при этом они сидят в общих скобках 2-го уровня.

    Из-за 2в без предобработки за O(n) проверить невозможно. Но предобработка хороша, если мы решаем кучу таких запросов, и с этим отдельный вопрос. В таком случае, вероятно, лучше использовать дерево отрезков, обрабатывающее каждый запрос за log n. Пока мне алгоритм понятен не до конца; если вы скажете, что действительно задача про кучу запросов — подумаю..
    Ответ написан
    Комментировать
  • Какую функцию использовать для построения такого графика?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариантов много. Считаем пока, что никаких требований к f(0) нет. Перемасштабируем наши переменные:
    x' = (x − 1)/9
    y = 8y' + 2.
    Тогда x' и y' будут от 0 до 1, в то время как x и y — 1…10 и 2…10. И тогда варианты.
    1. Степенная функция: y' = x'a, a = 0…1. Если a=½, то квадратный корень, ⅓ — кубический корень…
    2. Четвертушка эллипса: y' = sqrt(1 − x'²)
    3. Синус: y' = sin((pi/2)·x')

    Если же f(0) = 0, то масштабируем по-другому:
    x' = x/10
    y = 10y'
    Ответ написан
    4 комментария
  • Структура данных типа очереди, позволяющая быстро определить позицию элемента. Есть?

    @Mercury13
    Программист на «си с крестами» и не только
    Очередь, физически не перемещающая элементы (кольцевая или некое подобие std::deque) и позволяющая по указателю быстро определить позицию.

    Плюс любой индекс (хэш- или деревянный), элементы которого — указатели на элементы очереди. Если элементы очереди unique_ptr, то указатели будут именно на unique_ptr! Для «мусорных» языков (C#, Java) вместо указателей можно придумать какие-то идентификационные коды — например, сочетание из номера в пуле массивов и номера в массиве.

    Enqueue — вписываем элемент в индекс. Dequeue — удаляем из индекса. Обмен позициями — корректируем эти два элемента индекса.
    Ответ написан
    Комментировать
  • Как получить доступ к полям и методам неизвестного объекта?

    @Mercury13
    Программист на «си с крестами» и не только
    Это значит: объект класса B должен иметь (или не иметь) «товарища» класса C. Иметь не во владении, а по ссылке. А лучше не класса C, а его подмножества, реализованного как интерфейс (я его назвал IC). На A вообще чхаем — его задача собрать B и C в нужном виде, и всё.

    Смотрите шаблон проектирования Dependency Injection.

    class IC {   // interface
    public:
      virtual int getC() = 0;
      virtual ~IC() = default;
    };
    
    class C : public IC {
    public:
      int getC() final { return 42; }
    };
    
    class B {
    public:
      IC* buddy() const { return fBuddy; }
      void setBuddy(IC* aBuddy) { fBuddy = aBuddy; }
      void someJob() const { if (fBuddy) std::cout << fBuddy->getC() << std::endl; }
    private:
      IC* fBuddy = nullptr;
    };
    
    class A {
    public:
      A() { b.setBuddy(&c); }
    private:
      C c;
      B b;
    }

    Специально для тех, кто на Си++: в таком виде A неперемещаем из-за указателя c.fBuddy. Есть много способов исправить это — например, подправить конструктор копирования и операцию «присвоить» класса A.
    Ответ написан
    3 комментария
  • Как востановить бинарное дерево?

    @Mercury13
    Программист на «си с крестами» и не только
    Если одним префиксным/инфиксным/постфиксным — то, разумеется, нет. А если двумя — дело уже интереснее (при условии, разумеется, что все узлы разные).
    Ну, например, как восстановить дерево, которое было пройдено сначала префиксно, потом постфиксно (самый сложный и интересный случай). Признаюсь сразу: полное восстановление невозможно, ведь ситуации «без левых сыновей» и «без правых сыновей» различить нельзя.

    Если длины не совпадают, СТОП: некорректные данные.
    В префиксном обходе корень в начале, в постфиксном — в конце. Если они не одинаковы, СТОП: некорректные данные.
    Если в обходе один элемент — с этим всё понятно.
    Второй элемент префиксного обхода — левый сын. Ищем его в постфиксном обходе. Если он предпоследний — перед нами та самая ситуация «у дерева один сын», и рекурсивно запускаем алгоритм на обходах без корня.
    В противном случае выкусываем подстроки нужной длины (реально или виртуально), дважды запускаем алгоритм рекурсивно.

    Пример: у нас дерево.
         a
      b    c
    d  e   f

    Префиксный обход abdecf, постфиксный debfca. Корень a, левый сын b, он в постфиксном обходе на третьей позиции. Рекурсивно запускаем алгоритм на парах bde/deb и cf/fc.
    Ответ написан
    Комментировать
  • Алгоритм обхода площади за минимальное время?

    @Mercury13
    Программист на «си с крестами» и не только
    Если поворот «бесплатен», эквивалентны все несамопересекающиеся маршруты.
    Если нет — точного доказательства не вижу, но, по-видимому, тоже оптимальна (2h−2 поворота).

    UPD1. Если из-за каких-то особенностей прохождения поворотов на скорости нежелательны развороты на 180° — тогда спираль с первым отрезком по длинной стороне.
    Ответ написан
  • Режим работы из массива в одну строку?

    @Mercury13
    Программист на «си с крестами» и не только
    Скажем прямо: данная конструкция работает только если выходные дни в начале или конце недели. Если в середине — придётся расширять алгоритмы, да и труднолокализуема (языковые строки одновременно служат техническими ключами).

    Заводим три переменных: firstDay, lastDay, workHours. Поначалу они пустые строки.
    Проходимся по всем элементам.
    • Если рабочие часы совпадают с workHours — перезаписываем lastDay, и всё.
    • А если нет — проводим функцию dump, перезаписываем все три.
    После цикла принудительно проводим dump.

    Как должна работать функция dump.
    • Если workHours пусто — ничего не делаем.
    • Если результирующая строка непуста — добавляем разделитель.
    • В зависимости от того, совпадают ли firstDay и lastDay, добавляем «Пн» или «Пн-Пт».
    • Ну и, наконец, добавляем рабочие часы.
    Ответ написан
    Комментировать