• Как удалять элементы массива?

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

    std::vector<int> a = {1, 2 ,3 ,4 ,5};
    // Удалит элементы с l по r (l включительно, не удалит r).
    // Если надо удалить r-ый элемент, то добавьте +1 во второй аргумент.
    a.erase(a.begin()+l, a.begin()+r);


    Если же вы хотите делать руками, то надо просто посмотреть, куда двигаются элементы. Те, что до l - не двигаются. Те, что от l до r - исчезают. Те, что после r сдвигаются влево на r-l+1 позиций.

    for (i = l; i < n - 1 + l - r; ++i) {
      a[i] = a[i + r - l + 1];
    }
    // New length: n -1 + l - r;
    Ответ написан
    1 комментарий
  • Си: Как осуществить поиск ближайшего в массиве?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Бинарный поиск

    Только надо чуть чуть изменить. В конце вы останетесь на каком-то элементе ближайшем к искомуму слева или справа.
    Так что провертьте left и 2 соседних элемента на ближайшесть.
    Ответ написан
    Комментировать
  • У меня калькулятор выводит целое число почему?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    y = c / d;

    Вы делите целое число на целое. В языке С в этом случае происходит деление нацело. Чтобы в результате был float, вам надо один из операндов перобразовать во float/double. Можно или явно это написать, или просто прибавить 0.0:

    y = (c + 0.0) / d;
    Ответ написан
    2 комментария
  • Как задать матрицу X[5][7] на С?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Два цикла вложенных в друг друга. Внешний по строкам, 5 итераций. Вложенный по столбцам, 7 итераций. Внутри считывание одного числа с клавиатуры, но читаете не в какую-то переменную а в x[i][j].
    Ответ написан
    Комментировать
  • Как визуализировать эллиптическую кривую?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вы пробовали подставлять в вашу формулу a=-1, b=1?

    При x=-1, ваша формула выдаст y= 1.

    Почему она не рисует ничего, я не могу сказать, не видя весь ваш код. Возможно у вас там что-то ломается из-за корней из отрицательных чисел. Надо сначала проверить. что x^3+ax+b >= 0, и только в этом случае вычислять y и рисовать точки. И, да, вам надо цикл по x гнать с отрицательных чисел тоже.

    Можно сначала решить уравнение x^3+ax+b = 0, чтобы понять область определения функции.
    Ответ написан
  • Как найти все комбинации определенных слагаемых числа?

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

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

    Функция перебирает 2 варианта. Пусть отсавшаяся сумма s, а разрешенное максимальное число имеет номер i (они хранятся в каком-нибуть отсортированном a[]).

    1) Берем текущее максимальное слагаемое. Естественно, если оно помещается в остаток s >= a[i]. Кладем его к текущим слагаемым в массив и рекурсивно вызываемся от уменьшенного остатка, не меняя максимальное число - (s-a[i], i). Важно - если слагаемые хранятся в глобальной переменной, то надо после рекурсивного вызова "вернуть как было" - удалить только что добавленное слагаемое из массива.

    2) Пропускаем текущее максимальное число. Значит, больше его брать вообще нельзя. Вызываемся от (s, i-1). Естественно, этот вариант есть только если i>0.

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

    Ах да, чтобы этот метод хорошо работал имеет смысл слагаемые отсортировать по возрастанию. Чтобы сначала брались самые большие.

    Если среди возможных слагаемых нет 1, то этот полный перебор может заходить в тупики. На пример, доступны слагаемые 6 и 11, надо набрать 29. Алгоритм может пропустить 11 и попытаться набрать 29 одними шестерками, но этого никогда не получится. Эти лишние тупиковые ветки можно обрезать и ускорить таким образом решение в некоторых случаях.

    Для этого смотрите задачу о рюкзаке. Почти как в ней сделаейте динамическое программирование, которое будет считать, сколько способов собрать заданную сумму k мешьшими слагаемыми. После этого в рекурсивной функции вы можете сразу же возвращаться, если ДП говорит, что вариантов набрать s первыми i слагаемыми - 0.

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

    EDIT: Только заметил, что вам порядок важен и 1,2,3 считается отдельно от 3,1,2

    Изменения просты - рекурсивная функция теперь принимает только один параметр - сколько осталость добрать. Вместо двух вариантов она перебирает N вариантов - какое именно число из разрешенных взять.

    Оптимизация такая же. реализуете ДП, которое считает, сколько способов собрать заданное число и, если способов нет, возвращаемся из функции.
    Ответ написан
    Комментировать
  • Сколько существует путей и почему?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Количество сочетаний из 125 по 50. Или 125!/50!/75!
    Потому что он обязательно сделает 50 шагов вправо и 75 шагов вверх. В любом порядке. Т.е. всего 125 шагов из которых любые 50 - по горизонтали.
    Ответ написан
    1 комментарий
  • Как переместить данные по адресу?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не совсем понял вопрос, но, если вы имеете ввиду переписывания указателя на удаляемый элемент, то тут 2 подхода.

    1) Если функция рекурсивная, то пусть она возвращает новую голову списка. Если текущий элемент удалять не надо, то перепишите next на результат вызова от этого next и возвращайте текущую запись. Если удалять надо, то отчистите память и возвращайте next.

    2) Если функция работает циклом, что предпочтительнее, то вы можете просто помнить предыдущий элемент списка. Двигайте 2 указателя параллельно.
    prev = cur;
    cur = cur->next;
    Ответ написан
  • Как вывести парные числа в си?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Отсортируйте массив. Используйте стандартную функцию qsort.

    Потом пройдитесь по массиву. Выводите текущее число, если оно равно предыдущему и не равно следующему, или идет последним:
    if (a[i] == a[i-1] && (i+1== n || a[i+1] != a[i])

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    У вас две большие ошибки с языком питон. Вы в цикле в alg итерируетесь по списку add, меняя его. Так делать нельзя. Ломаются итераторы и вы пропускаете половину элементов.

    Вместо этого используйте цикл while:

    while add:
      item = add[0]
      add.remove(item)
      s.append(item)
    ...


    Вторая большая ошибка, в питоне списки передаются по ссылке! Поэтому s, который у вас параметр рекурсивной функции, на каждом уровне один и тот же список. Но при выводе множества вы сразу же возвращаетесь из функции, не удаляя item из s. Вам надо чтобы все изменения в s были отменены по выходу их функции. Перед return делайте s.remove(item).

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

    Еще по коду:
    range(n) в python возвращает 0..5. У вас там цикл по ребрам в __main__ и там идет обращение к i-1 в массиве graf. Т.е. обращение к [-1]. Вряд ли вы это хотели. Работает по чистой случайности, потому что в питоне a[-1] дает последний элемент.

    И вообще, вы матрицу смежности строите, но нигде не используете.

    Вместо функции check(), вы сделайте нормальный список смежности один раз, а то просто глаз режет от неоптимальности.
    neighbors = [[] for i in range(count_vershin)]
    for edge in graf:
      neighbors[edge[0]-1].append(edge[1]-1)
      neighbors[edge[1]-1].append(edge[0]-1)
    Ответ написан
  • Как ускорить программу?

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

    Для понимания алгоритма, сначала сделаем немного другую версию за O(n), а потом соптимизируем до константы.
    Вы вместо сравнения с сортированным массивом пройдитесь по массиву и смотрите, что для всех соседних элементов следующий более или равен предыдущему.
    Следующий шаг - заведите массив bool на n-1 элемент и храните в нем пометки, что в данной позиции массив отсортирован. При помене местами двух элементов надо пересчитать 4 позиции в этом массиве. Потом пройдитесь по массиву и проверьте, что там все элементы true. Пока все еще работает за линию и еще хранит лишний массив.
    А теперь последний шаг - можно не проходиться по массиву bool каждый раз, если поддерживать счетчик, сколько там истинных элементов. После ввода массива list надо будет заполнить массив bool-ов и подсчитать, сколько там true. При перестановке a и b у вас максимум 4 элемента в массиве bool могут поменяться. Вот при этих изменениях вы счетчик пересчитывайте. Просто тупо при каждой записи в этот массив вычтите 1 из счетчика, если текущее там значение true и прибавьте 1, если новое значение true.
    Ответ написан
    Комментировать
  • Нужна помощь в языке С, касательно матриц, возможно циклов -?

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

    Можно писать так:
    if ((i > 0 && a[i-1][j] > a[i][j]) || (i < n-1 &&  a[i+1][j] > a[i][j])) {
      // текущий элемент меньше хотя бы одного соседа в том же столбце.
    }

    еще можно так:
    if ((i == 0 || a[i-1][j] > a[i][j]) && (i == n-1 ||  a[i+1][j] > a[i][j])) {
      // текущий элемент меньше всех соседей в том же столбце.
    }



    Комбинируя условия на циклы через || и && можно составить любое нужное вам условие, которое смотрит только на существующих соседей. Но тут важен порядок операций. В C++ (да и почти везде, на самом деле) условия выполняются слева направо и прекращают выполнение, как только результат становится известен. Вот, в первом примере сначала идет проверка на i>0 а потом обращение к массиву через логическое И. Поэтому, если программа будет обрабатывать первый элемент в строке уже на первом условии она заметит, что все условие обязательно false, ведь там стоит &&. И условие с обращением к массиву не будет произведено никогда.
    Ответ написан
    Комментировать
  • В чём разница в скорости работы между перебором всех состояний игры и функций Шпрага-Гранди?

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

    Но она обладает замечательным свойством - если состояние игры можно разложить на несколько независимых игр и игорк в свой ход может сделать ход в любой из игр, то функция Гранди может быть подсчитана как xor значений для всех состояний. По умному это называется, что игра является суммой игр. В некоторых задачах это позволяет колоссально сократить простарнство состояний.

    Один пример - игра Ним. Есть несколько кучек камней. За свой ход игрок может взять сколько угодно камней из любой кучки. Проигрывает тот, кому не останется камней. В простом переборе вам придется в качестве состояния хранить вектор количеств камней в каждой кучке. Но ведь тут стостяние очевидно раскладвается на под-игры: каждая кучка - своя отдельная игра. Причем, функция Гранди тут тривиальна - это просто количество камней. Вот и получается решение игры Ним - взять xor размеров всех кучек. Если не 0, то состояние выгрышное. Надо взять из какой-то кучки столько камней, чтобы получился xor, равный 0.

    Еще пример - есть плитка шоколада. Игроки ее ломают вдоль клеток. За свой ход игрок может взять любой прямоугольный кусок и разломить его как-то вдоль клеток (если там более 1x1 клеток, конечно). Проигрывает тот, кто не сможет сделать ни одного хода. Опять же, при простом переборе пришлось бы хранить в состоянии размеры всех кусоков. Тут ОЧЕНЬ много вариантов. А с функцией Гранди - достаточно рассмотреть состояния вида "одна плитка размера n x m". После одного хода у вас будет 2 плитки, но меньшего размера. Вы уже знаете для них функцию гранди, XOR'ите их и получаете функцию для возможного перехода.
    Ответ написан
    4 комментария
  • Когда использовать ООП?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    ООП - это не только, когда вы берете какие-то сущности из предметной области и оборачиваете каждую в объект, который что-то умеет делать. Это больше подход к организации кода. Вы делите задачу на подзадачи, а данные на обособленные части, абстрагируете детали внутри объектов. Это позволяет снижать сложность архитектуры. Теоретически любую программу можно написать внутри одной огромной функции с кучей goto. Но так никто не делает, потому что это невозможно поддерживать и невероятно сложно написать. ООП - это логическое продолжение процедур. Теперь вы не только какие-то части программы абстрагируете в одном месте, но теперь еще и данные вмести с ними.

    Мне нужен объект, который будет хранить состояние/данные, и есть общие операции над этим состоянием?


    Вопрос: что значит нужен? Всегда можно взять глобальную переменную, написать функции, которые это состояние принимают и что-то с ним делают. Но довольно часто организация в виде объекта просто удобнее.
    Ответ написан
    1 комментарий
  • Как получить всевозможные комбинации массива PHP?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Подсчитайте руками, сколько комбинаций для массива из 1,2,3,4 элементов? ответ будет 1,3,7,15 - степени двойки минус один. Подумайте, откуда это берется? Каждый элемент может или быть в ответе, или нет. 2 варианта. Премножаем все, получаем степень двойки. Но это учитывает варинат пустого ответа, поэтому один надо вычесть.

    Тут есть 2 подхода - рекурсивная функция перебора, которая или берет или пропускает текущий элемент. В конце, если хоть один элемент был взят - выводит текущий массив.

    Второй подход - перебирать битовую маску. Каждое число от 1 до 2^n будет в двоичной системе числения представлять какой-то вариант выбора разрядов. Поэтому можно прогнать цикл от 1 до 2^n, потом посмотреть на биты этого числа и брать соотвествтующие числа из массива.
    Ответ написан
    Комментировать
  • Как перенести строку в двумерном массиве, если количество элементов больше определенного количества?

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

    Самое простое решение - в цикле вывода символов выводить '\n', если текущий символ 20-ый, 40-ой и т.д. Например, можно проверять (i+1) % 20 == 0.
    Ответ написан
    Комментировать
  • Какой алгоритм решения данной задачи?

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

    Вещественные числа в Си, например - это тип float. Корень - sqrt(). Пи - M_PI. В формуле есть e в степени чего-то там. Почти в любом языке уже есть функция exp().

    Все решение - читаете 2 числа, потом присваивайте вещественной переменной один, деленное на второе число, помноженное на sqrt() от двух, умноженного на Пи. Это все умноженное на exp() от первой переменной, домноженной на себя, поделенной на 2 и на вторую переменную в квадрате.
    Ответ написан
    1 комментарий
  • Содержит ли массив определенные числа?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вариант простой - перебрать все участки 3x3 (смотрите левый верхний угол - это 2 цикла от 0 до width-3 и от 0 до height-3) и проверить, что они хорошие.

    Для проверки можно или 1) проверить, что все числа от 1 до 9 и разные, или 2) проверить, что там ровно один раз каждая из цифр встречается. Второй вариант короче и быстрее, но для него вам придется завести массив счетчиков от 0 до 9. Перед каждой проверкой он занулен. Обойдите ваш 3x3 блок и увеличьте соответствующий счетчик (что-то типа count[a[beg_x+i][beg_y+j]]++). Только не забудьте проверить, что число от 1 до 9, чтобы не вылезать за границы массива. Потом пройдитесь по массиву счетчиков циклом от 1 до 9 и проверьте, что там везде стоят единицы.
    Ответ написан
    Комментировать
  • Как решить эту комбинаторную задачу?

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

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

    Вот и считайте, сколько вариантов поставить палку перед каждой единицей. Надо подсчитать расстояния между каждой парой единиц и перемножить. Если единиц вообще нет - ответ 0, если одна - то 1.

    Можно сделать за один проход, если запоминать, где стояла предыдущая единица.

    int64_t CountWaysToSplit(std::string s) {
      int last_one = -1;
      int64_t res = 1;
      for (int i = 0; i < s.length(); ++i) {
        if (s[i] == '1') {
          if (last_one >= 0) res *= i - last_one;
          last_one = i;
        }
      }
      return last_one >= 0 ? res : 0;
    }
    Ответ написан
    Комментировать
  • Как реализовать калькулятор со скобками на си(через обратную польскую запись)?

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

    Если же от вас требуется что-то более самостоятельное, то делайте так - найдите в строке операцию с наименьшим приоритетом (ту, которая будет выполнена последней). Рекурсивно выведите обратную польскую запись для левой и правой половины, потом выводите/выполняйте операцию.

    Чтобы найти операцию - проходитесь по строке, считая сколько сейчас открыто скобок. Запомните позицию самого правого встреченного "+"/"-" и "*"/"/". Если ничего не нашли - значит можно откусить внешнюю пару скобок (если скобок нет, то вся строка - число). Иначе, если есть + или - - это та самая последняя операция. Если таковой нет - то будет * или / - берите ее.

    Это работает за квадрат в отличии от алгоритма по ссылке, но зато пишется элементарно.
    Ответ написан
    2 комментария