• Как найти разницу двух чисел в массиве рекурсивно?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Можно было бы как-то так:
    static int pres,qres;
    static int[] A;
    static int M=10;
    
    bool Find1(int p,int q){
      if(A[q]-A[p]==M){ 
        pres=p; qres=q;
        return true;
      }
      if(A[q]-A[p]<M || q-p<2) return false;  
      int k=p+(q-p)/2;
      if(Find1(p,k) || Find1(k,q)) return true;
      return Find2(p,k,k+1,q);
    }
    
    bool Find2(int p1,int q1,int p2,int q2){  // p1<=q1<p2<=q2
      if(A[p2]-A[q1]>M || A[q2]-A[p1]<M) return false;
      if(A[p2]-A[p1]==M){
        pres=p1; qres=p2; return true;
      }
      if(A[p1]==A[q1] && A[p2]==A[q2]) return false;
      if(A[q1]-A[p1]>A[q2]-A[p2]){
        int k=p1+(q1-p1)/2;
        return Find2(p1,k,p2,q2) || Find2(k+1,q1,p2,q2);
      }else{
        int k=p2+(q2-p2)/2;
        return Find2(p1,q1,p2,k) || Find2(p1,q1,k+1,q2);
      }
    }

    (функция Find1 ищет пару в одном фрагменте, Find2 - в двух непересекающихся фрагментах). Но я совершенно не представляю, какая получится сложность. Не исключено, что O(n*log(n)). Зато рекурсия используется по назначению :)
    UPD. Немного поправил условия - здесь часто лучше сравнивать не индексы, а сами элементы.
    Ответ написан
    6 комментариев
  • Что не так с алгоритмом для поиска наибольшей неубывающей подпоследовательности?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    В этой задаче нельзя обойтись "текущей подпоследовательностью". Надо держать самые длинные подпоследовательности, заканчивающиеся на разные элементы (чем больше элемент, тем длиннее должна быть подпоследовательность, заканчивающаяся на него), и когда приходит новый элемент, то присоединить его к самой длинной из последовательностей, к какой возможно (причём старую последовательность сразу выбрасывать нельзя - она ещё может пригодиться), а потом выбросить неоптимальные (последовательность такой же длины, что и другая, но заканчивающаяся на больший элемент).
    Например, для последовательности [1,2,7,8,9,5,6,3] вам придётся помнить
    [1,2,7,8,9]
    [1,2,5,6]
    [1,2,3]
    [1,2]
    [1]
    Любая из этих последовательностей может быть началом правильного ответа.
    Так что начало решения у вас правильное. Но в векторе d должны храниться не числа, а их индексы (и поиск должен быть более сложным), а массив prev надо модифицировать так: prev[i]=d[j-1].
    Для примера [1,2,7,8,9,5,6,3] получаем
    d={-1,0,1,7,6,4,-1,-1,-1,...}, prev={-1,0,1,2,3,1,5,1}
    (значение -1 используется для обозначения ситуации "нет такого индекса").
    Ответ написан
    3 комментария
  • Как в хабрастатьи вставляют математические формулы?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Часто используют сервис latex.codecogs.com . Какое-то время назад он испортился - разрешил показывать только небольшое количество формул на странице, но сегодня, вроде бы, работает, как раньше.
    Ответ написан
    Комментировать
  • Как решить задачу об огурцах?

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Придумываете условную единицу "сантик".
    Считаете, что выигрыш каждого (в сантиках) равен произведению его ставки на процент выигрыша (неважно, считать выигрыш от 0 до 1 или от 0 до 100).
    Вычисляете общий выигрыш в сантиках.
    Вычисляете курс сантика исходя из того, что суммарный выигрыш 10000.
    Пересчитываете выигрыш каждого.
    Если сумма ставки - S(X), а процент выигрыша - V(X), то
    C=10000/sum(S(X)*V(X)) - курс сантика
    W(X)=S(X)*V(X)*C - окончательный выигрыш.
    Ответ написан
    Комментировать
  • Поясните правила 57 и 58 в MISRA C. Почему break, continue - плохо?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Единственный разумный ответ, который я увидел - что если в блоке (теле цикла) кто-то захочет написать malloc, а в конце - парный к нему free (или, например, fopen/fclose), и не заметит, что в теле цикла есть break или continue, то могут возникнуть проблемы.
    И в стандарте 2004 г. запрет на break ослабили. Запрет на goto и continue оставили.
    Ответ написан
    Комментировать
  • Как помочь организму адаптироваться к резкому изменению графика?

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Нужно многоугольник делить делителями. Координаты делителей относительные. Например это может быть процент или расстояние от первой точки многоугольника. Пока это неважно.

    На самом деле, это очень важно.
    Если под "делителем" вы имеете в виду отрезок, каждый конец которого определяется как точка, делящая какой-то уже построенный отрезок в определённом (известном и неизменном) отношении, то задачу решить можно.
    На примере вашего 5-угольника. Пусть его вершины - ABCDE, заданные по часовой стрелке, AB - верхняя сторона. Пусть первый (самый левый) делитель PQ, точка P делит отрезок AB в отношении 3:7, точка Q делит отрезок DE в отношении 6:4. Точка R (левый конец внутреннего делителя) делит отрезок PQ тоже в отношении 6:4.
    Запишем:
    P = 0.7*A + 0.3*B
    Q = 0.4*D + 0.6*E
    R = 0.4*P + 0.6*Q
    Здесь сложение и умножение точек выполняется покоординатно, и если точка K делит отрезок MN в отношении m:n, то мы пишем K=M*(n/(m+n))+N*(m/(m+n)).
    Подставив P и Q в последнее уравнение, получим R=0.28*A+0.12*B+0.24*D+0.36*E - выражение координат этой точки через координаты вершин исходного пятиугольника. Таким образом, для каждой точки достаточно хранить n чисел - коэффициенты в этом выражении.

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Чтобы найти точку "в плоскости", вам нужно задать в ней систему координат. То есть, выбрать точку начала координат O(x0,y0,z0) и два базисных вектора X=(x1,y1,z1) и Y=(x2,y2,z2). Судя по тому, что вы говорите про "декартову систему координат", векторы должны быть единичной длины и перпендикулярны друг другу.
    Добавляете к системе вектор Z, параллельно которому идёт проектирование. Из условия непонятно, рассматриваете вы только ортогональную проекцию, или общий случай параллельной проекции.
    В случае ортогональной всё просто - не нужно даже возиться с матрицами:
    вектор Z вычисляется как векторное произведение X и Y, но он нам не нужен вообще: если проектируемая точка P имеет координаты (x,y,z), то её проекция Q будет иметь координаты (в системе координат плоскости)
    x'=(P-O,X)=(x-x0)*x1+(y-y0)*y1+(z-z0)*z1
    y'=(P-O,Y)=(x-x0)*x2+(y-y0)*y2+(z-z0)*z2.
    В случае косоугольной проекции вычисления сложнее - надо умножать вектор (P-O) на матрицу, обратную к матрице, составленной из X,Y,Z. И там главное не запутаться, где строки, а где столбцы.
    Ответ написан
  • В чем разница между Ассемблером и Компилятором?

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

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Как-нибудь так? Правда, это C#, но разница должна быть небольшая.

    public static String moveLetters(String a) {
            int L=a.Length;
            char[] chars = new char[L];
            for(int x=0;x<L;x++) chars[x]=a[x==1 ? L-L%2-1 : x-2*(x%2)];
            return new String(chars);
    }
    Ответ написан
    1 комментарий
  • Какие преимущества CISC архитектуры перед RISC?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    CISC лучше там, где всё ещё очень мало памяти для программного кода. Если, конечно, такие места ещё остались.
    Ответ написан
    Комментировать
  • Как запрограммировать нахождение стационарного распределения методом Гаусса?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Переписываете первые 3 строчки в виде
    p1*(0.1967-1) + p2*0.4561 + p3*0.3321 + p4*0.2982 = 0
    p1*0.0750 + p2*(0.0553-1) + p3*0.1986 + p4*0.0325 = 0
    p1*0.2239 + p2*0.4863 + p3*(0.0291-1) + p4*0.3382 = 0

    Четвёртая не нужна - она является их линейной комбинацией.
    Добавляете к ним строчку
    p1*1+p2*1+p3*1+p4*1=1
    Получаете квадратную систему линейных уравнений. Решаете её методом Гаусса на любом известном вам языке - и всё.
    Ответ написан
    1 комментарий
  • Стоит ли учить ассемблер для глубокого понимания архитектуры компьютера?

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

    Mrrl
    @Mrrl
    Заводчик кардиганов
    double y=x/2;
      bool isEven=(fabs(y-round(y)) < EPS);
    Ответ написан
    Комментировать
  • Как найти красный квадрат на сером фоне (C#)?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Посмотрите на LockBitmapData (работа со строчками Bitmap напрямую). Там можно работать гораздо быстрее, чем через GetPixel.
    И действительно, ищите красные точки с шагом 4 или 5 (можно и 8, но есть риск промахнуться, если квадрат оказался чуть меньше).
    Ответ написан
  • Как аппроксимировать синусоиду по трем параметрам?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Если X идёт с равномерным шагом, то МНК не нужен.
    Сначала сводите задачу к Y=a+d*sin(X)+f*cos(X).
    Довольно очевидно, что a=sum(Y)/n (поскольку sum(sin(X))=sum(cos(X))=0).
    Далее, умножаете обе части исходной формулы на sin(X):
    sum(Y*sin(x))=a*sum(sin(X))+d*sum(sin(X)^2)+f*sum(sin(X)*cos(X))
    Выполняются условия sum(sin(X))=sum(sin(X)*cos(X))=0, sum(sin(X)^2)=n/2 (если n > 2). Отсюда d=sum(Y*sin(X))*2/n. Аналогично, f=sum(Y*cos(X))*2/n.
    Ответ написан
    6 комментариев
  • Какой добавить коэффициент для поворота формулы?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    r=sin(2*(phi+phi0)), где phi0 - угол поворота. Но она повернёт только кривую, а оси оставит на месте.
    Ответ написан
    1 комментарий