Ответы пользователя по тегу Алгоритмы
  • Как реализовать функцию копирования бит со смещениями в src и/или dst и не кратным 8 количестве бит?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Самое эффективное - использовать какой-нибудь SSE (гуглите shift bits sse. Лучше всего, мне кажется, подойдет _mm_slli_epi64). Но там очень много кода и случаев будет. Придется отдельно разбирать случаи сдвига влево и вправо, отдельно вычленять биты, которые SSE операция при сдвиге бы потеряла и записывать куда надо.

    Следующий по эффективности вариант - это читать в int64_t, и там сдвигать биты. Придется сначала из переменной доставать старшые/младшие 1-7 бит и писать их отдельно, потом сдвигать биты и записывать куда надо. Используйте memcopy для чтения/записи 64-ех бит. Еще можно ускорить, если отдельно обработать первые несколько байт до 64-битного выравнивания, и потом придется еще обрабоать отдельно лишние 0-7 байтов в конце, если их количество не делится на 8.
    Ответ написан
  • Какой алгоритм используется при возможности 2 неудачных попыток?

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

    Пусть C(n,k) - сколько надо в худшем случае бросков, если мы знаем, что предмет разбивается при бросании с 1..n и можно сделать k неудачных бросков.

    С(n,k) = min_i=1..n-1 ( max(C(i,k-1), C(n-i, k)) )) + 1


    База - C(1, k) = 0; C(n, 1) = n-1.
    Ответ написан
    2 комментария
  • Как разбить числа по группам так, чтобы в группах находились близкие по значению числа?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Надо ввести какую-то метрику - какая-то числовая оценка, которая говорила бы вам, почему [[1,2],[3,4],[5,6]] лучше чем [[1,2,3,4],[5],[6]]. Например, можно взять максимальную разность двух чисел в любой группе. Или сумму квадратов расстояний от всех чисел до среднего в их группе. Или минимальное расстояние между числами в разных группах (это надо максимизировать).

    Потом можно применять какой-то из известных методов кластеризации, в зависимости от выбранной метрики. В случае одного измерения, как у вас (просто числа) можно еще применить и динамическое программирование. Этот метод работает для практически любой вменяемой метрики. Считайте функцию F(n,k) - лучшая возможная метрика если первые n чисел разбить на k групп. Для пересчета надо перебрать, сколько чисел идет в последнюю группу (i), и пересчитать метрику на основе F(n-i, k-1). из всех вариантов выбрать лучший.
    Ответ написан
    Комментировать
  • Какой алгоритм вычисления кратности чисел более эффективен?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Судя по названию функции (sum) вам надо найти сумму чисел. Это делается в одно действие без циклов вообще.

    Если бы были нужны только числа делящееся на 3, то их сумма - f(n, 3)=3*floor(n/3)(floor(n/3)+1)/2. Эта формула получается вынесением 3 за скобки в сумме и дальше применением формулы армфметической прогрессии.

    Чтобы взять сумму делящихся на 3 или 5 надо взять сумму делящихся на 3, прибавить сумму делящихся на 5 и вычесть сумму делящихся на 15. Потому что делящиеся на 15 были подсчитанны 2 раза в первых слагаемых. Т.е. ответ - f(n,3)+f(n,5)-f(n,15)
    Ответ написан
    Комментировать
  • Влезет ли параллелепипед в четверть цилиндра?

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

    Как проверить прямоугольник на впихивание в сектор? Если коробка помещается, ее можно в секторе вертеть и двигать, пока она не будет касаться границы сектора тремя вершинами. Получаются случаи: угол коробки совспадает с уголом сектора (диагональ прямоугольника <= радиуса), одна точка на прямой стороне сектора и две на круглой, 2 угла на двух прямых сторонах и одна на круглой.

    Два последних случая надо порисовать, ввести какие-то переменные (например во втором случае можно ввести x и y - длины отрезков от угла сектора до углов прямоугольника) решить систему квадратных уравнений (длины сторон заданны, третья точка лежит на окружности) и проверить, что четвертая, свободная точка лежит внутри.

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

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

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

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

    Еще надо помнить про специфику работы мониторов - эти самые числа в RGB задают квадратные корни интенсивности свечения разных пикселей.

    Еще, возможно будет легче сначала преобразовать RGB в какой-нибудь YUV или HSL.
    Ответ написан
    1 комментарий
  • Как ускорить перебор элементов списка?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Можно в несколько раз с оптимизировать, переписав на C++ c векторизацией (SSE там всякие). Тогда сравнение двух строк будет 1-2 инструкции вместо 15. Еще можно распаралеллить вычисления. Но все эти оптимизации все равное не позволят вам быстро считать для 100000 строк. Что уж говорить, сама матрица будет занимать минимум 10 гигабайт, если аккуратно на C писать или типизированный numpy массивы использовать. А так она и все 20 и 40 гигабайт займет запросто.

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

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

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вам надо арктангенс брать от отношения, а не тангенс (y2-y1) / (x2-x1).
    Ответ написан
  • Как вычислить ценовой рейтинг товара?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Это называется интерполяция. Вы знаете, что f(a) = 10, f(b)=5. Вам надо найти f(c), при чем f должна попадать под здравый смысл (монтонная, непрерывная функция).

    например, можно взять линейную инерполяцию, тогда f(x) = 10-(x-a)/(b-a)*5.
    Ответ написан
    1 комментарий
  • Какие есть алгоритмы упаковки прямоугольников?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Только перебор. Или, если подойдёт достаточно хорошее решение - всякие эвристики с жадностями.
    Ответ написан
  • Это правильная реализация бинарного поиска?

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

    Чтобы работало быстро вам надо не менять lst, а помнить индексы границ текущего куска.

    Ещё, вам надо останавливаться, когда рассматриваемый кусок станет пустым, чтобы решение не вылетало, если искомого числа в списке нет.

    И последнее, в питоне есть операция целочисленного деления - //. Используйте ее вместо приведения к int после деления.
    Ответ написан
    2 комментария
  • Алгоритм для нахождения количества пересечений отрезков в последовательности(списке)?

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

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

    Это если вам надо весь массив, как в примере, выводить. Не знаю специфику вашей задачи, может эффективнее будет класть в массив пары {координата, +-1} и сортировать. Потом точно также обойти слева направо поддерживая счетчик.
    Ответ написан
    4 комментария
  • Как понять цифры хэмминга на пальцах?

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

    Есть у вас список уже сгенеренных чисел, изначально содержит только 1.

    Вы добавляете в список сделющее число, пока не наберете необходимое количество.

    Поддерживайте 3 указателя (изначально на первое число), которые указывают на первые неиспользованные числа для домножения на 2, 3 и 5.

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

    Пример:
    шаг 1.
    указатели: 1, 1, 1
    список: {1}
    варианты:1*2, 1*3, 1*5. Лучший - 2.

    шаг 2.
    указатели: 2, 1, 1
    список: {1, 2}
    варианты:2*2, 1*3, 1*5. Лучший - 3.

    шаг 3.
    указатели: 2, 2, 1
    список: {1, 2, 3}
    варианты:2*2, 2*3, 1*5. Лучший - 4.

    шаг 4.
    указатели: 3, 2, 1
    список: {1, 2, 3, 4}
    варианты: 3*2, 2*3, 1*5. Лучший - 5.
    Ответ написан
  • Итерационное вычисление больших степеней числа по цифрам?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Есть неалгоритмический способ ускорить ваше решение - храните в каждой ячейке массива не одну цифру - а несколько. Фактически, проводите вычисления в системе счисления 10000, вместо 10. Или даже 1000000000 - но тогда надо временные вычисления (умножение) делать в int64_t, чтобы переполнения не было.

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

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

    Но в таком виде алгоритм будет даже медленнее на больших числах. Ему потребуется O(log K) умножений большого на большое (которое делается за O(L^2), где L - длина числа, которая будет O(K)). Итоговая сложность этого алгорима будет O(K^2 log K).

    Когда как ваше текущее решение делает K коротких умножений (Каждое - O(K)) - всего O(k^2) операций. Но если применять быстрое умножение длинных чисел через быстрое преобразование Фурье то итоговая сложность будет O(K log^2 K log log K). Для power=100 особо вы разницы не почуствуете, даже медленнее будет, но вот при каких-нибудь 10000 уже будет заметно быстрее.

    Советую попробовать обычные оптимизации, прежде чем браться за преобразование фурье.

    Еще, вместо хранения конца числа в виде особого значения 10 - вам стоит отдельно хранить длину числа в какой-то переменной с говорящим названием (хотя бы len). Тогда код будет сильно читабельнее.
    Ответ написан
    2 комментария
  • Как посчитать БЖУ?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это задача о многомерном рюкзаке (multi-dimensional knapsack). Каких-то простых трюков, как с обычным одномерным рюкзаком тут нет. Только перебор с отсечениями.

    Еще можно свести задачу к целочисленному линейному программированию. Вводите переменные - сколько штук каждого пункта съели, составляете линейные уравнения. Потом можно это все скормить какому-нибудь решателю. Сейчас много библиотек и они довольно быстро такие задачи щелкают. Гуглите "integer linear programming solver".
    Ответ написан
  • Как определить последовательность действий?

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

    Проблема в том, что состояний очень много. Поэтому граф не генерируется, а строится на лету. А дальше все-равно в этом графе запускается какой-то алгоритм поиска пути. Например A*. Или dfs со всякими эвристическими оптимизациями. Главное это накрутить достаточно оптимизаций, чтобы алгоритм не касался слишком большого количества состояний - потому что все просмотренные состояния надо хранить как-то в памяти.
    Ответ написан
    3 комментария
  • Алгоритм поиска минимального количества ходов, требуемых для приведения всех элементов к одному числу (Python)?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Во-первых, в вашем алгоритме цикл while вообще не нужен. Сколько нужно операций +1, чтобы из a получить a+12345? Ровно 12345. Вам надо просто вычесть одно число из другого.

    Далее, мысль должна быть такая: Вот вы знаете, сколько нужно операций, чтобы все числа в массиве привести к X. Вопрос: сколько операций вам понадобится для приведения всех чисел к X+1? (Подсказка - если число было меньше X, то теперь понадобится на 1 операцию больше. Если число было больше X - то понадобится на 1 операцию меньше).

    Теперь вам надо посмотреть, подумать и выбрать оптимальное X, которому вы будете приводить все числа. Ваш вариант с max/2 не оптимален.
    Ответ написан
    5 комментариев
  • С чего начать изучение алгоритмов?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Почитайте Кнут "искусство программирования" а также Кормен "алгоритмы: построение и анализ".
    Ответ написан
    Комментировать
  • Как сымитировать правильную скорость выполнения различных сортировок путём usleep?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы наткнулись на важное свойство ассимптотического анализа. O(n^2) -означает, что на достаточно больших n, время работы будет примерно n^2 с точностью до константы. Эта самая константа может быть хоть 0.5, хоть 10000000.

    Сравните 2 алгоритма:
    // n(n-1)/2 инкремента.
    for(i = 0; i < n; ++i){
      for (j = i+1; j < n; j++) {
        cnt1++;
      }
    }
    // n^2 инкремента.
    for(i = 0; i < n; ++i){
      for (j =0; j < n; j++) {
        cnt2++;
      }
    }


    Оба алгоритма имеют O(n^2) сложность, но один делает примерно в 2 раза меньше операций.

    Суть в том, что хоть алгоритмы и работают с одинаковой ассимптотикой, они могут работать разное время! Особые странности могут быть при маленьких n. O(n log n) алгоритм часто может быть медленнее O(n^2) алгоритма. Поэтому все настоящие реализации сортировок для маленьких массивов запускают более тупые квадратичные алгоритмы.

    Если же вы хотите показать только ассимптотику, то возьмите n побольше, и тогда эти 30% будут незаметны по сравнению с десятикратным замедлением O(n^2) относительно O(n log n). Или нормируйте ваши сортировки. Искуственно ускорьте одни алгоритмы и замедлите другие, чтобы получить именно тот результат, который вы хотите. Но это как-то нечестно что ли. Если же вы все-таки хотите именно этого, назначьте каждой сортировке время C\*n^2 или С\*n\*log n миллисекунд. Прогоните алгоритмы сортировки без визуализации, подсчитайте, сколько операций замедления вы бы сделали (тот же самый код, что у вас, только вместо usleep() делайте sleep_count++). В конце подсчитайте коэффициент замедления - сколько каждый usleep должен спать, чтобы суммарно sleep_count их спал заданное время. И запускайте каждую сортировку уже с подсчитанными параметрами для usleep.
    Ответ написан
    Комментировать