Ответы пользователя по тегу Программирование
  • В задаче сказано: "возрастающая конечная арифметические прогрессия из различных целых отрицательных целых чисел" - что это должно сказать решающему?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Знать не нужно почти ничего - только формулу n-го члена и суммы арифметической прогрессии.
    В этой задаче всё выражается через новый член, добавленный математиком (пусть это -b), количество членов, бывших до того (n) и шаг прогрессии d (натуральное число).
    Слегка поигравшись с формулами, получаете, что изменение разности D=n*b*(2*b+(n+1)*d). Несложно убедиться, что должно быть b>0. Всё, что вам нужно - подобрать натуральные b,d,n, чтобы условие выполнялось.
    Ответы:
    1) -5,-4,-3 (добавлено -2)
    2) не бывает: нужно, чтобы b*(2*b+13*d)=120, т.е. 120/b-2*b было положительным и делилось на 13. Понятно, что b должно быть меньше 8 и быть делителем 120. Перебирая возможные значения (это все числа от 1 до 6), получаем, что решений нет.
    3) n=15, прогрессия -19,-18,...,-5 (добавлено -4).
    В последнем случае перебираете возможные значения b*d (чем оно меньше, тем больше возможно n). Оказывается, что при b*d=1,2,3 решений нет, а при b*d=4 - есть.
    UPD. Выше сказали про "олимпиадные задачки" - боюсь, что это правда. Для олимпиадных задачек особых знаний не нужно - но нужна система знаний, чтобы быстро найти верный путь в лабиринте возможных подходов.
    Ответ написан
    Комментировать
  • Существует ли алгоритм реорганизации списка оптимальный по количеству перестановок?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Если есть операция IndexOf для поиска элемента, то оптимальное число перестановок достигается так (превращаем L1 в L2):
    for(int i=0;i < L1.Count;i++){
      while(L1[i]!=L2[i]){
         L1.swap(i,L2.IndexOf(L1[i]));
      }
    }

    При каждом обмене текущий элемент L1[i] ставится на то место, на котором он стоял бы в списке L2, и больше с этого места не уходит.
    Ответ написан
    2 комментария
  • Самая сложная программа в мире?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Может быть, это программа для машины Тьюринга с 6 состояниями, которая выводит 3.5*10^18267 единиц и останавливается? en.wikipedia.org/wiki/Busy_beaver

    Ещё один вероятный кандидат - эмуляция игры "Жизнь" на ней самой (со скоростью 1/10000000). Там даже про язык сложно говорить.
    Ответ написан
    Комментировать
  • Как найти длину перпендикуляра с точки на отрезок?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    double L=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
    double PR=(x-x1)*(x2-x1)+(y-y1)*(y2-y1);
    bool res=true;
    double cf=PR/L;
    if(cf<0){ cf=0; res=false; }
    if(cf>1){ cf=1; res=false; }
    double xres=x1+cf*(x2-x1);
    double yres=y1+cf*(y2-y1);

    В (xres,yres) будут координаты ближайшей точки отрезка, а переменная res покажет, перпендикуляр получился, или нет.
    Ответ написан
  • 3D триангуляция?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    В общем, делается так.
    Пусть фигура задана набором треугольных граней с известной ориентацией. В каждом ребре сходится чётное число граней (возможна, например, фигура из двух тетраэдров, склеенных по ребру), и при обходе любого ребра ориентации граней, сходящихся в нём, чередуются (например, идут грани ABC, BAD, ABE, BAF). Даже если в исходной модели таких странных рёбер нет, они могут возникнуть на промежуточном этапе.
    Выбираем любые две грани со следующими свойствами:
    - у них есть общее ребро AB;
    - при обходе этого ребра они являются последовательными
    - внутренний угол между этими гранями меньше 180 гр.
    Такие грани найдутся всегда. Пусть это ABC и BAD.
    Рассмотрим тетраэдр ABCD. Проверим, нет ли у него внутри других вершин. Если нет - заменим грани ABC и BAD на CAD и BCD (вырезав, тем самым, ABCD из модели). Если есть - возьмём ту вершину E из них, которая ближе всего к грани ABC, и заменим грань ABC на три грани ABE, AEC, EBC.
    После этого просмотрим грани, и если оказалось, что какая-то грань встречается дважды с противоположными ориентациями (ABC и ACB) - выбрасываем обе копии.
    Процесс повторяем, пока все грани не исчезнут.
    Всё.
    Ответ написан
    4 комментария
  • Где, когда и как лучше использовать лямбда-выражения?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Я использую лямбда-выражения в двух случаях:
    - когда это действительно "выражение", т.е. всё вычисление укладывается в одну формулу;
    - когда для вычислений нужно использовать значения переменных текущего метода.
    При этом я помню, что "под ковром" компилятор создаст для каждого контекста с лямбда-выражением отдельный класс, и захваченные переменные будут полями этого класса (а само лямбда-выражение - его методом). Причём они будут использоваться, как поля, не только для кода, вычисляющего это выражение, но и для всей работы с этими переменными. Так что, если в конкретном месте приходится думать об эффективности, то надо всё взвесить.
    Ответ написан
    1 комментарий
  • Используются ли в программировании дифференциальное и интегральное исчисления?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    В программировании не используется. Используется в конкретных приложениях, для которых используется также и программирование. Программисту, в общем, всё равно, что программировать, решение дифф.уравнения или подсчёт какой-нибудь статистики - были бы формулы. Дифференциальное и интегральное исчисления используются на два шага выше - когда происходит формализация конкретной практической задачи и выбор математической модели (ещё даже не алгоритмов!) для неё.
    Иногда, правда, соответствующие подходы используются уже при поиске алгоритмов для других задач. Скажем, один из алгоритмов решения полиномиальных систем (метод гомотопий) можно свести к решению хитрого дифференциального уравнения. Но, в любом случае, это не программирование, а алгоритмистика.
    Ответ написан
  • Как решить задачу про разрез(написать программу)?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Сначала проверяете, есть ли свеча в центре. Если есть, то очевидно, нельзя (любой разрез, делящий торт пополам, проходит через центр).
    Потом для каждой свечи находите направление на неё из центра. В большинстве языков это делается вызовом функции atan2(y,x) (в предположении, что центр находится в точке (0,0)). Она выдаёт угол в радианах, лежащий в промежутке от -pi до pi.
    Сортируете углы по возрастанию: a1<=a2<=...<=an.
    Если an-a1 < pi-eps, то все свечи лежат внутри угла, меньшего pi, и разрез есть.
    Если для какого-то k a{k+1}-ak > pi+eps, то есть пустой угол, больший pi, и разрез тоже есть.

    Сложности возникают, когда an-a1 или a{k+1}-ak очень близки к pi, и надо точно проверить, больше угол, чем pi, меньше, или равен. Здесь всё зависит от жестокости авторов задачи.
    Если числа заданы, как целые, не превосходящие по модулю 10^9, то достаточно посчитать определитель x{k+1}*y{k}-x{k}*y{k+1}, и по его знаку определить, с какой стороны линия, соединяющая свечи, пройдёт от центра. Произведения укладываются в int64, и всё просто.
    Если числа целые и не превосходят 10^18, то дело хуже. Существуют алгоритмы проверки, не выходящие за int64 (специально написанный алгоритм Евклида), но возможно, что проще воспользоваться длинной арифметикой.
    Хуже всего, если координаты - вещественные числа произвольного формата. Боюсь, что тут придётся писать свой парсер - простого хорошего способа надёжно проверить, что свечи с координатами, скажем (1.2E220, 2.7E-180) и (-2.8E200, 6.3E-200) лежат строго на одной прямой, проходящей через центр, я не знаю.
    Ответ написан
    Комментировать
  • Зачем вы пошли в разработчики?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    1) Так получилось. Оказалось, что самому программировать проще, чем объяснять алгоритмы другим.
    2) Вполне.
    3) Пусть выбирают что хотят. Хоть разработчиком, хоть ветеринаром, хоть пилотом истребителя. Лишь бы им нравилось.
    4) Совершенно неважно. Лишь бы можно было вдоволь заниматься интересными делами.
    5) Собираюсь, после технологической сингулярности. При первых возможностях аплоадинга пойду осваивать виртуальный мир.
    Ответ написан
    Комментировать
  • Сколько времени вы максимально искали баг?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Если баг воспроизводится, и время от запуска программы до момента, когда эффект, вызванный этим багом, меньше 10 минут (под дебагером), то обычно дня хватает. При условии, что он не вызван неправильным пониманием поведения чужой программы (скажем, плохо документированным форматом их входных данных, которые должны создаваться моей программой).
    В случае, если баг возникает редко, зависит от аппаратуры и компьютера, на которых идёт запуск, то могут уйти и годы. Анализируются лог-файлы, уточняется место, где что-то пошло не так, придумываются дополнительные промежуточные проверки, дополнительная отладочная печать - и программа снова отправляется на работу, до следующего проявления бага.
    Ответ написан
    Комментировать
  • Почему именно синус?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    В этой задаче синус не нужен.

    double r=sqrt(x*x+y*y);
    double cf=1+10/r;
    double x1=x*cf,y1=y*cf;

    (x1,y1) - координаты искомой точки.
    Ответ написан
    3 комментария
  • Цикл в 100.000 итераций vs "умного" цикла?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Что известно про заполненные ячейки? Они образуют непрерывный фрагмент? Прижат ли он к началу массива, или к концу, или у него известна минимальная длина?
    Если ваш алгоритм применить к массиву, в котором заполнены ячейки с 10001 по 19999, он их не заметит, и скажет, что массив пуст. Так и предполагается?
    Если заполнен непрерывный участок с неизвестной заранее длиной L, то есть простой способ найти его за O(N/L) операций (а потом обработать за O(L)).
    Ответ написан
    2 комментария
  • Как построить 3D модель, используя плоскость и линию?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Соединяются точки, находящиеся либо на соседних строках матрицы на одном кадре, либо на одной и той же строке на соседних кадрах. В результате получается сетка из четырёхугольников. Их можно разделить на треугольники по более короткой диагонали.
    Если на какой-нибудь строке зелёной точки не найдётся - в модели будет дырка.
    Ответ написан
    4 комментария
  • Математика и олимпиадное программирование?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Математика, в общем, и не нужна. Для геометрических задач полезно знать геометрию, уметь работать в координатах. Для задач, в формулировке которых фигурирует "вероятность" и "математическое ожидание" - полезно знать, что это такое. Собственно, всё. Гораздо важнее знать много алгоритмов, какой где применяется и как его написать для данной ситуации.
    Ответ написан
  • Взлом шифра Вернама(одноразовый блокнот). Как сделать?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Предполагаем, что известно, на каком языке сообщения, и статистика распределения символов (а также сочетаний по 2, 3 символа...)
    Зависит от того, сколько у нас сообщений.
    Если их достаточно много, то строим статистику символа с каждым порядковым номером по всем сообщениям (символ k встретился P[k] раз). Эта статистика должна получаться из стандартной статистики L для языка как P[k]=L[k^c], где c - искомый символ. Для каждого c считаем вероятность того, что на этом месте оказался именно он, и дальше начинаем искать наиболее вероятный текст для какого-нибудь сообщения.
    Если сообщений только два, то придётся использовать распределение групп символов, смотреть, из каких сочетаний наиболее вероятно получится фрагмент из C1^C2, и дальше распутывать их с помощью каких-нибудь цепей Маркова. Не знаю, получится ли.
    Сильно облегчит дело, если сообщения - фрагменты обычных ASCII-файлов, со всеми знаками пунктуации и переводами строк. Можно воспользоваться тем, что перевод строки имеет код 0D,0A, пробел - 20, другие знаки пунктуации - от 21 до 3F, большие буквы - от 41 до 5A, маленькие - от 61 до 7A (это если текст английский. Для русского ещё лучше). Смотрим на поведение битов 40 и 20. Если в каком-то месте в разных закодированных сообщениях значения бита 40 различны, значит в некоторых это буква, в остальных - знак пунктуации. Причём, буква вероятнее в тех, в которых более частое значение. Немного похимичив, получаем разделение текстов на слова, строки и предложения. Заодно в части сообщений проявляются некоторые буквы. Дальше работаем с распределением одно-, двух- и трёхбуквенных слов. Может быть, повезёт.
    Ответ написан
    5 комментариев
  • А у вас есть тетрадка, куда вы записываете наброски кода?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Раньше использовал большие 160-листовые тетради формата A4. Записывал всё подряд - планы, структуры программ и алгоритмов, описания на псевдокоде, в сложных случаях - куски кода, заметки при отладке... Пару лет назад попытался перейти на S Note на Самсунге, но пришел к выводу, что экран слишком маленький - тетрадка даёт гораздо лучшее разрешение. Сейчас использую для записей жёлтые блокноты (формата A5), думаю, что скоро опять вернусь к тетрадкам. Если они ещё будут в продаже.
    Ответ написан
    2 комментария
  • Как найти повторяющееся слово в строке?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Попробуйте алгоритм Кнута — Морриса — Пратта. Если с его помощью найти строку в самой себе, то ответом будет как раз сдвиг на повторяющееся слово. Но придётся повозиться с таблицей побочных переходов.

    В общем, получается вот такой простой алгоритм (правда, на C++):
    int maxrepword(char *A){
    	int *ref=new int[strlen(A)];
    	int b=0,s=1;
    	ref[0]=-1;
    	while(A[s]){
    		if(A[s]==A[b]) ref[s++]=b++;
    		else if(b==0) ref[s++]=-1;
    		else b=ref[b-1]+1;
    	}
    	delete[] ref;
    	return s-b;
    }

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Можно просто периодически читать/просматривать код, вспоминая, что к чему, как оно выглядит, откуда вызывается и кого вызывает, в каких ситуациях работает та или иная часть кода... Чтобы ориентироваться на местности, надо по ней иногда гулять, и не бояться заблудиться :)
    Ответ написан
    Комментировать
  • Развивается ли способность к решению нестандартных задач?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Не развивается.
    Можно нарабатывать опыт решения таких задач, оттачивать приёмы для конкретных классов задач, расширять кругозор, чтобы видеть больше приёмов, учиться видеть всё более далёкие аналогии - но это приведёт только к тому, что у вас будет шире спектр задач, которые вы будете считать стандартными. Столкнувшись с очередной нестандартной задачей, вы окажетесь в той же ситуации, в какой были в начале - что придётся её крутить так и этак, пробовать разные подходы, сводить задачу к другим - эквивалентным или более общим, и пытаться решать их... пока не найдёте подходящий приём.
    Даже задача проверки теоремы на истинность алгоритмически неразрешима. Решение нестандартных задач - из той же серии.
    Ответ написан
    2 комментария
  • Как из математика адаптироваться-переквалифицироваться в программиста?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Боюсь, что будет очень трудно. Все эти юнит-тесты, соблюдение стилей программирования, документация, системы поддержки версий через какое-то время заставят забыть, что ты математик. Я сейчас стараюсь держаться от них подальше: попал на такое место, где нужен именно математик-алгоритмист, и, хотя пишу много кода, программистом себя считать не могу. Это опасное положение: если придётся менять работу, будет трудно найти что-нибудь подобное.
    Так что чтобы переквалифицироваться в программиста, надо изучать современное программирование с нуля. А чтобы научиться придумывать и реализовывать алгоритмы - брать книжку по алгоритмам, и разбирать и писать их все подряд. Через какое-то время придумать себе задачу с околоматематической формулировкой, попытаться её решить (пример: построить все неэквивалентые триангуляции многообразий - с краем и без, содержащие данное число треугольников). Потом другую задачу, и т. д.
    Ответ написан
    Комментировать