• Как усовершенствовать алгоритм для уравнения Диофанта?

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

    Там по вашей ссылке в задаче есть подсказка: уравнение можно переписать в виде (x-2y)(x+2y)=n

    Отсюда получается решение: Перебирайте все делители n, не превосходащие корень. Пусть делитель d, тогда второй множитель будет n/d.

    Осталось решить систему линейных уравнений:

    x-2y=d
    x+2y=n/d


    Решается в уме - x=(d+n/d)/2, y=(n/d-d)/4

    Отслось только учесть диофантовость уравнения - ответ должен быть неотрицательные целые числа. Значит, надо чтобы оба делителя d, n/d давали одинаковый остаток от деления на 4 и 2. Ну и d<=n/d, но это учтется перебором делителя до корня.

    Вот и все решение - циклом переберите делитель до корня, убедитесь, что он и оставшийся множитель дают один и тот же остаток по модулю 4, вычислите x и y и выведите их.
    Ответ написан
    Комментировать
  • На какой шифр это похоже?

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

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

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

    Во первых, тут есть неоднозначность. Может быть так что теги A,B,C попарно несовместимы, но заодно попарно несовместимы теги A,D,E - куда относить тег A, в какую группу?

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

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

    Еще есть Алгоритм Брона — Кербоша. Он перебирает все максимальные клики.
    Ответ написан
  • Preimage - атака нахождения прообраза. Теория + практика. Пофантазируем?

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

    Посмотрите, сколько ваша видео карточка выдает хэшей. Беглый гуглеж дает что-то порядка 3Ghash/s Поделите 10^k на 3*10^9 - получите максимальное время в секундах. Можно ожидать, что в среднем понадобится половина этого времени.

    Если вы используете кластер, то вам понадобится (сколько времени вы насчитали выше)/(сколько времени вы готовы ждать) одинаковых компов в кластере. Если это обычные юзеры, то нельзя сильно нагружать и понадобится в 10 раз больше компов.

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Смотрите критерии планарности - надо плясать от них.

    Например, если взять первый критерий - граф не содержит подгарфа, который есть подразделение K5 или K3,3.

    Очевидно, что n=4 всегда планарен сам граф. Доказывать нечего. Остались случаи n=5,6,7.

    Если сам граф не содержит такого - то он уже планарен, доказывать нечего. Если же сам граф содержит K5 или K3,3 то вам надо доказать, что дополнительный граф не может содержать такие подграфы.

    n=8, очевидно, тут не подходит, потому что можно взять K5, прикрутить к нему рядом K3 (Без новых ребер между кликами). Дополнительный граф при этом будет K5,3 - который содержит в себе K3,3.

    Советую рассмотреть 3 случая и доказать что они все не возможны. Граф и дополнительный граф содержат по K5; оба содержат по K3,3; один содержит K5, а другой K3,3.

    Например, первый случай весьма прост - при n<8 подграфы пересекаются как минимум по 3 вершинам. В прямом графе из-за K5 они обязаны иметь между собой ребра, а из-за K5 в дополнительном графе - они обязаны не иметь между собой ребер. Противоречие.
    Ответ написан
    Комментировать
  • Что не так с алгоритмом создания максимального числа из исходного, используя двоичную СС?

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

    Тут есть 2 куска 1110. Но за первым идет "010", а за вторым "011". Начинать со второго - выгоднее.

    В этой задаче очень маленькие ограничения - можно полностью перебирать все возможные числа и брать максимальное. Можно даже не переводить в двоичную систему, а воспользоваться битовыми операциями.
    Когда вы узнали, сколько битов в числе, то самый младший бит x можно получить как x&1. Сдвинуть все биты числа на одну позицию вправо - это x >> 1. При этом младший бит пропадает. Чтобы вставить новый бит b слева нужно сделать x | (b << k) - тут k - номер позиции этого бита, считая с 0.

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

    И так, для развития: Если бы ограничения были слишком большие (число в десятки тысяч бит), то тут пришлось бы применять умные строковые алгоритмы. Это была бы задача на поиск лексикографически максимального циклического сдвига. Решается с помощью суффиксного дерева, суффиксного массива или суффиксного автомата.
    Ответ написан
    2 комментария
  • Как вывести определенное значение в центр массива при его разной размерности?

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

    Раз задача построить концентрические вложенные квадраты, то есть 2 подхода.

    Простой для понимания, но менее эффективный (но все-равно отлично быстрый для смешных ограничений в задаче) - напишите функцию, которая в двумерном массиве рисует квадрат заданного размера вокруг центра. Это тупо 4 последовательных, не вложенных цикла. Каждый рисует одну сторону квадрата. Тупо цикл до n, где n - длина стороны квадрата. Там одна координата фиксирована, а другая пробегает вдоль стороны. Надо чуть-чуть подумать, и составить формулы, какие строки и столбцы будут закрашены.

    Заведите двумерный массив, заполните его пробелами, и потом циклом от n%2 до n с шагом 2 рисуйте квадраты.

    Второй, более эффективный, подход - это немного подумать. Возьмите клетчатый лист, или в редакторе каком-либо нарисуйте ответ для n=9,10. Подумайте над паттернами. Первая строка будет всегда из n #. Вторая будет #, n-2 " ", #. Следующая "# #...# #" и так далее.

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

    Подсказка для формулы - имеет значение, как близко строка к середине массива и четность n. Расстояние до середины можно получить как abs(n/2 - i)
    Ответ написан
    4 комментария
  • Что делает в данной ситуации yield()?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Читайте документацию.

    Yield говорит планировщику, что сейчас хорошо бы текущий поток вытеснить.

    Зачем он тут нужен? В сильно конкурентной среде это позволит другим потокам что-то доделать и сократить накладные расходы на попытки захватить мьютекс. Но вообще говоря тут он не нужен. И вообще надеяться на yield - плохая идея. Планировщик может его и вообще проигнорировать.
    Ответ написан
    Комментировать
  • Какое это дерево, у элемента которого более двух родителей?

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

    Если же рассматривать произвольный граф с кучей родителей и детей, то скорее всего вы имеете в виду ациклический ориентированный граф.
    Ответ написан
    Комментировать
  • Как реализовать распознавание кривых на canvas?

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

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

    Составим функцию ошибки f(x1, y1, x2, y2) = (X(i/n)-x_i)^2+(Y(i/n)-y_i)^2. Тут x_i, y_i - координаты i-ого пикселя в нарисованной кривой, пронумерованные от 0 до n, X(t), Y(t) - координаты точки на кривой Безье - линейные комбинации x1, x2 и y1, y2 с известными вычисляемыми от t коэффициентами. Это фактически сумма квадратов расстояний от каждого пикселя до неизвестной кривой. Ее можно минимизировать подобно методу наименьших квадратов - считайте производную по всем переменным, приравнивайте к 0. Получите 4 неизвестные и 4 линейных уравнения. Можно вообще на бумажке руками методом Краммера решить, а можно алгоритмом Гаусса подсчитать.

    Тут есть допущение, что i-ый пиксель будет аппроксимироваться t=i/n точкой на кривой. Вообще говоря, это не гарантированно, но в качестве некой грубой меры оптимальности подойдет. Может вообще отлично работать будет и так, я не знаю. Поэксперементируйте. Но еще можно потом честно искать ближайшую точку на кривой к заданному пикселю как оптимум полинома 6-ей степени от t, когда все опорные точки кривой фиксированы. Тут надо брать производную, находить ее нули и среди них брать лучшее t. Чтобы найти нули полинома 5-ой степени можно рекурсивно брать производную, находить нули полинома меньшей степени, и потом на каждом монотонном отрезке искать пересечение с OX бинарным поиском. Или использовать метод Ньютона. Это давно решенная задача - должно быть куча готовых решений.

    Когда вы так научились считать расстояние от кучки пикселей до кривой Безье, можно локально градиентным спуском по 4-м координатам x1, x2, y1, y2 улучшать эту правильную метрику с оптимума полученного грубой метрикой.

    Вот мы и умеем аппроксимировать кучку пикселей одной кривой. Заодно мы получаем метрику близости кривой к пикселям. Но надо сделать ее не зависящей от длины - поэтому складывайте квадраты расстояний и делите на количество пикселей.

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

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

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

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

    Попробуйте (*p)++.
    Ответ написан
    2 комментария
  • Как убрать нілики из ответа даного кода, ответ правильний только нулі виводить перед ответом?

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

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы выводите всегда 2N цифр. Даже если в ответе их меньше.

    Надо циклом найти в массиве самую последнюю не нулевую цифру и выводить с нее.

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

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

    Уберите ненужные переменные. Еще, зачем у вас там i % columns?

    Похоже, надо в output.txt выводить, а не в stdout.

    Еще, советую выводить перевод строки всегда, и не пропускать его на последней строке вывода.

    Чтобы не было проблем с пробельными символами - читайте в двух вложенных циклах до rows и columns по одному char (а не string до eof). Это и ввод упростит и сделает его более безопасным ко всяким артефактам в тестах.
    Ответ написан
  • Как грамотно остановить объект при столкновении?

    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 Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Кубическая функция с первым коэффициентом 1, как у вас, уходит в минус бесконечность слева и плюс бесконечность справа. Она может не иметь экстремумов или иметь два - максимум левее минимума.

    Если экстремумов нет - будет возрастающая функция, с одним вещественным корнем всегда. Если экстремумы есть, то надо или чтобы они оба были меньше 0, или оба были больше.

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

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

    n=5,m=3, первый шаг - поделить. осталось n=3, m=2. Второй шаг - опять делим, остается m=2, n=1. Третий шаг - делим, остается n=1, m=0, четвернтый шаг - видим 0, остановились.

    для n=m=5 ответ 1, возможно, потому что в алгоритме стоит проверка m==0 || m == n.
    Ответ написан
  • Почему функция не возвращает указатель на объект класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    if (!a)	{
        a->s = s;
        cout << 5;
        return a; //ошибка, не возвращает указатель на обьект класса
    }


    У вас тут a==NULL - пустой указатель. Вы пытаетесь его члену что-то присвоить (то. что программа не упала - вам дико повезло). потом вы возвращаете этот же пустой указатель.

    Вам надо создавать новый объект через new в этом случае.
    Ответ написан
    3 комментария
  • Как решить задачу на вероятность, схема Бернулли?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    У вас ошибка: надо еще P30(0) прибавлять.

    Какой-то более простой формулы мне придумать не удалось, и она вряд ли есть. Если руками вывести формулы для маленького количества банков, то там все-равно получается полином n/2-ой степени, т.е. от 15 слагаемых никуда не уйти.

    Я думаю, в этой задаче у вас приняли бы просто символьную записть в виде суммы.

    Если нужно числа - можно написать программу, или считать на калькуляторе. Начинайте с 0.7^30. Делайте m+, домножайте на 3/7*30/1, потом на 3/7*29/2, и так далее (нажимая m+ каждый раз), пока 15 слагаемых всего не наберется.

    Или вбить в wolframalpha и получть 98.3%.
    Ответ написан
    Комментировать
  • Каким образом получить такой набор? Какие методы использовать?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это похоже на задачу set cover. Легких алгоритмов тут нет. Только полный перебор с отсечениями. Еще всякие методы отжига и эволюционные алгоритмы могут найти хорошее решение. Ну и, задачу можно переформулировать в виде integer linear programming и решать какой-то из существующих библиотек.

    Если количество слов маленькое (типа 25-30), то можно решать динамическим программированием по маске покрытых слов.

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