• Почему постоянно выводится расстояние 0(Алгоритм Дейкстры для городов)?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы выводите d[begin_index], это расстояние до начальной вершины. Естественно там 0 будет. А выводить надо расстояние до конечной. Надо end использовать (и выводить после того, как вы end нашли).
    Ответ написан
    Комментировать
  • Как найти кратчайший путь в лабиринте, двигаться в котором можно только вперед и направо?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы правильно поняли, что у вас вершинами в гарфе являются клетка+направление, по которому пришли.
    Но раз у вас вот это вершины, то вам и пометки о песещении вершины надо делать в трехмерном массиве. А начальных и финальных вершин у вас по 4 штуки: клетка x 4 направления (на самом деле, начинать достаточно только с 2 направлений, но неважно).
    Ответ написан
    3 комментария
  • Какой алгоритм использовать, чтобы: разбить массив чисел так, чтобы суммарная разница между максимальным и минимальным числом была максимальна?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ага, ДП тут отлично входит. F(n) - ответ на задачу для префикса длины n. Там перебираете длину последней группы x и берете в качесвте ответа max(a[n-x]..a[n-1]) - min(a[n-x]..a[n-1]) + F(n-x). По всем l<=x<=r выбераете максимум. Если n < l, то ответ - минус бесконечность.

    Это будет решение за O(n^2). Что-нибудь за O(n log n) я так сходу придумать не могу.
    Ответ написан
    6 комментариев
  • Как в C++ создать массив с неизвестным числом элементов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно через new[] выделить массив:
    cin >> n;
    int *array = new int[n];
    // ввод, и работа с массивом.
    
    // не забудьте в конце удалить выделенную память.
    delete[] array;
    Ответ написан
  • Как оптимизировать код с++ с рекурсией в времени?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно попробовать сделать микрооптимизации: функция F реализуется одним циклом (делите, пока делится на 10, потом берите последнюю цифру). S тоже можно считать циклом, а не рекурсией.

    Но скорее всего, этого не хватит. Это решение за O(q*log(q)). Ограничения на числа в условии не видно, но если там что-то порядка 2000000000, то ваша программа будет считать несколько секунд.

    Надо хорошенько подумать и применить математическую хитрость. Надо как-то считать числа в интервале p...q пачками, а не каждое отдельно.

    Что такое функция F? Это последняя ненулевая цифра в числе. Давайте вместо суммы значений F счиатать, сколько чисел из интервала дадут вот такое вот значение? Ну просто по последней цифре сложно сказать, сколько там чисел, а вот если еще зафиксировать количество пропущенных в конце нулей, то уже становится понятно, как подсчитать это. Вот допустим, вы считаете последнюю цифру d и там должно быть 3 нуля. Тогда вы ищети числа вида "xxxd000". Или их можно представить в виде d*1000+x*10000 для произвольного неотрицательного x. И вот вам надо подсчитать сколько таких чисел в интервале [p,q]. Ну решите 2 уравнения: d*1000+x*10000 >= p и d*1000+x*10000 <= q

    Таким образом вы за несколько арифметических действий и одну проверку можете подсчитать, сколько чисел вида "xxxd000" будут в интервале. Осталось циклом перебрать d от 1 до 9 и количество нулей от 0 до длины q. И вот у вас решение за O(log(q)).

    Edit:
    Вот код быстрого решения:
    int S(int p, int q) {
      int sum = 0;
      for (int d = 1; d < 10; ++d) {
        for (int tens = 1; tens <= q; tens *= 10) {
          int left = p - d*tens;
          if (left < 0) left = 0;
          else left = (left + 10*tens-1)/(10*tens);
          int right = q - d*tens;
          if (right < 0) right = -1;
          else right /= 10*tens;
          sum += d*(right - left + 1);      
         }
      }
      return sum;
    }
    Ответ написан
  • Как устроен вывод в задаче?

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


    не сумма всех взятых ребер, а стоимость максимального из них.

    1 2 (2) и 2 3 (1) - максимальная стоимость 2 (max(1,2)).

    1 3 (3) - максимальная стоимость 3 max(3). 3 больше 2, значит ответ выше лучше.

    Так задача легче, чем с суммой.
    Ответ написан
    8 комментариев
  • Какую формулу использовать?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Можно делить на цело в конце. 110*300/330 даст ровно 100. Если же в котле осталось не делящееся нацело количество монет, то будет округление вниз: для 301 монеты тоже получится 100 вместо 100.(3).

    Надо хранить долю юзера в виде рационального числа - отдельно числитель и знаменатель.
    Ответ написан
    Комментировать
  • Справится ли алгоритм с задачей по поиск слов в словаре?

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Внутренние циклы выполняют суммарно максимум 8(r-l-1) операций. На каждой итерации внешнего цикла r-l уменьшается на 2. Т.е. всего операций будет 8(n-2)+8(n-4)+8(n-6)...

    Можете эту арифметическую прогрессию подсчитать и оценить?
    Ответ написан
    Комментировать
  • Как вернуть двумерный массив?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    int masInt[3][5] - вот такие массивы c фиксированными размерами на самом деле хранятся одним куском и индексацию компилятор вычисляет сам. Это не int**, а int[][5]. Только этот тип нельзя вернуть из функции.

    Что бы вернуть именно указатель на указатель, вам надо его так и завести и не забыть выделить по строкам:
    int** masInt = new int* [3];
    for (int i = 0; i < 3; ++i) {
      masInt[i] = new int[5];
    }


    Не забудьте только потом удалить все это добро через delete[]:
    for (int i = 0; i < 3; ++i) {
      delete[] array[i];
    }
    delete[] array;


    Но вообще, лучше не парить себе мозги и возвращать std::vector<std::array<int,5>>.
    Ответ написан
    1 комментарий
  • Как реализовать многопоточность на C++?

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

    Вот в 0 секунд у вас I1..I5 сгенерировали заявки, они пападают в накапители и сразу же из них в каналы. В 3 секунды K1 обработал заявку и свободен. Взял одну из накопителя. В 4 секунды K2 освободился, взял заявку из накопителя. В 5 секунд источники снова сгенерировали заявки... и т.д. Это можно просимулировать.

    Реализуется это с помощью приоритетной очереди событий. В нее вы складываете новые события, а в основном цикле достаете оттуда событие с минимальным временем. На c++ это будет что-то вроде:
    std::priority_queue<pair<int, Event>, std::vector, std::greater> queue
    .

    Еще вам надо написать классы для источника, накопителя, блокиратора с условиями (не понял, что это) и накопителя.

    Например, источник в момент создания кладет в очередь событие "в 0 секунд я создам заявку". При выполнении этого события, во-первых, создается и кладется в очередь новое событие "в t+5 секунд я создам заявку". Во-вторых, надо посмотреть, куда заявки из этого источника попадают. Если это накопитель, то заявка пихается в него.

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

    Класс канала при получении заявки создает событие во время t+время обработки заявки, что он освободится. При вы полнении этого события канал смотрит, к чему он подключен и если там не пустой накопитель, то забирает оттуда первую заявку.

    Класс Event должен как-то запоминать какой объект это событие выполняет. А основной цикл должен этот код вызывать (и передавать туда время события).
    Ответ написан
    Комментировать
  • Инструмент для сохранения всех вариантов сочетаний по заданной маске?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Есть. Называется python + модуль itertools.
    import itertools
    import string
    
    def generate_strings(length):
        chars = string.ascii_letters + string.digits
        for item in itertools.product(chars, repeat=length):
            yield "".join(item)
    
    for string in generate_strings(3):
        print(string)


    Для 8 символов поменяйте 3 в коде на 8.
    Ответ написан
    Комментировать
  • Как получить хендл без OpenProcess?

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

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

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

    А теоремы эти используют как раз, чтобы доказать, что граф не планарный. Тогда вы берете как-то стягиваете его вершины и получаете K33 или K5. Значит не планарный.

    Доказать отсутствие таких стягиваний очень муторно. Надо перебирать все варианты. Типа, что будет если мы вот эти 2 вершины стягиваем в одну? А если нет? В первом случае, а стягиваем ли мы туда вот эту третью? А если нет? И так у вас 100500 случаев. Если очень граматно выбрать вершины, то есть шанс, что количество вариантов будет не слишком большое. Если видите, что стянутый граф можно нарисовать без самопересечений, дальше стягивать не надо.
    Ответ написан
    2 комментария
  • Как из массива байтов HEX сделать сделать DEC?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Можно без перевода в десятичную систему считать. Столбиком, как в начальной школе. Это будет работать даже если ваши числа длиннее 4 байт.
    byte summ[N];  // N >= skoll_len+sprice_len.
    for (int i = 0; i < skoll_len; ++i ) {
      word carry = 0;
      for (int j = 0; j < sprice_len; ++j) {
        carry += summ[i+j] + (word)skoll[i] * sPrice[j];
        summ[i+j] = carry % 256;
        carry /= 256;
      }
      if (carry > 0)
        summ[x_len + y_len - 1] += carry;
    }


    Тут три неочевидных момента. При прибавлении одной строки из умножения столбиком все переносы считаются сразу одним проходом. Во-вторых, там может быть какой-то лишний перенос в конце, но только на одну дополнительную ячейку, потому что x < 256^x_len, y <256^x_len, а значит x*y < 256^(x_len+y_len), значит не будет никакой записи дальше ячейки x_len+y_len-1. И последнее, carry по пути нигде ни разу не переполнится, ибо максимальная сумма там может быть 255*255+255+255 < 256*256.

    P.s. Но если у вас числа уж очень длинные, то гуглите быстрое преобразование фурье + длинное умножение.
    Ответ написан
    3 комментария
  • Как узнать, входит ли игрок1 (x,y,z) в поле игрок2 (x,y,z)?

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

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

    Но это медленно. Для усокрения, надо хранить всех игроков в какой-то трехмерной структуре данных. Например, квадро-дерево. Там для ускорения поиска в каждой вершине храните сколько там игроков есть, и при рекурсивном спуске не идите в те вершины, для которых обрамляющий прямоугольник не пересекается с окружностью для игрока, относительно которого вы соседий ищите. Когда дошли до листа с игроками, каждого из них проверьте - досаточно ли они близки для добавления в ответ. Для упрощения, вы вместо окружности пересекайте с обрамляющим прямоугольником квадрат описанный вокруг окружности. Сильно упрощает код, хоть и даст немного лишних проверок.
    Ответ написан
  • Как решить данную задачу при помощи префиксного дерева?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Конечно, на эту задачу можно натянуть префиксные деревья (это же вы бор/trie имеете ввиду, да?). Но тут какая-то растянутая сова получается.

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

    Но это нисколько не эффективнее наивного итеративного подхода, где вы это же максимальное количество упорядоченных букв поддерживаете идя по строке слева направо, сбрасывая в 0 на пробелах.
    Ответ написан
  • Не работает math.pow, что я делаю не так?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Скобки в делителе в переменной numerator пропустили.
    Еще, у вас имена переменных кривые. Зачем-то назвали два множителя "числитель" и "делитель". Причем дробь целиком считается в первой.
    Ответ написан
  • Как работает рекурсия, и как мне исправить код?

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

    Во-первых, удалите flag. Ужасный, отвратительный подход. Что он означает? Зачем он вам нужен? Разве нельзя обе части выполнять в цикле всегда, вместо того, что бы чередовать их очень не читаемым и запутанным методом?

    Далее, надо поддерживать какой-то инвариант. У вас там 2 переменные в цикле first и last. Что вы поддерживаете? Все элементы до first не превосходят pivot, а все после last не меньше его? Определитесь с этим и докажите себе, что после каждой итерации цикла этот инвариант сохранится. Вместо того, чтобы следить за тем, где у вас ведущий элемент, просто запомните в переменную его значение.

    Если не разберетесь, смотрите на код в википедии, например.
    Ответ написан
  • Выдает ошибку, как ее можно исправить?

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