Ответы пользователя по тегу C++
  • Как найти общие элементы у трех массивов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Какой ужасный алгоритм! Лучше запихнуть первые два массива в hash-set (std::unordered_set). А потом при проходе по третьему массиву просто проверить, что этот элемент есть в первых двух set-ах.

    Если элементы могут повторятся, но выводить надо только один раз, то заведите еще один unordered_set, куда добавляйте элементы, которые вы добавили в ответ. Естественно, перед добавлением элемента в ответ, проверьте, а не содержится ли он уже в этом set-е.

    И код получится раз в 10 меньше и работать будет на пару порядков быстрее.
    Ответ написан
  • Как найти точки пересечения 2х фигур с++?

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

    upd: На этом же сайте есть все что нужно для проверки пересечения окружности и отрезков.
    Ответ написан
    2 комментария
  • Как в шифре с магическим квадратов заполнить пустые клетки произвольным символом?

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    b = func(a);

    Вот тут вы взяли ссылку, которую вернула func и скопировали значение в переменную b. Поэтому ниже &b выведет вам адрес переменной b, а не то, что вы хотели.

    Возвращать ссылки бывает удобно, когда надо вернуть значение без копирования и оно всегда существует. Потому что функция, возвращающая указатель, вообще говоря, может вернуть и nullptr. По уму, надо бы этот указатель проверить перед разыменованием. А вот ссылки - они всегда куда-то указывают.
    Ответ написан
    3 комментария
  • Справа налево или слева направо представляются данные в виде битов в ячейках?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Правильный ответ - ни так и не эдак. Никак. Сравнивать указатели не из одного и того же массива - undefined behavior. Это было недавно в статье на хабре. Там ссылаются на раздел 3.3.8, "Relational operators".

    Более того, у вас там в программе еще UB: нельзя обращаться к данным в переменной long через указатель short - Это нарушение strict aliasing.

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

    На практике - никаких лево и право там не существует, есть только младшие и старшие адреса, читайте про big/little endian порядки байт. Они там бывают и так и эдак в разных архитектурах. В x86, например, младший байт имеет меньший адрес.
    Ответ написан
    Комментировать
  • Как получить id потока в процессе C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно получить список всех потоков одного процесса через Thread32First/Thread32Next (пример).

    Ищется в гугле буквально по "winapi list threads".
    Ответ написан
    Комментировать
  • Как написать функцию расшифровки этого алгоритма?

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

    Шифрование делает 34567890 итераций, вам надо сделать столько же. Внутри порядок операций надо развернуть, чтобы отмены выполнялись в обратном порядке. Если в строке 2 операции, например умножение и вычитание, то сначала надо выполнить обратное к вычитанию и только потом обратное к умножению.

    Обратные к вычитанию и сложению - сложение и вычитание соответственно. Если шифрование прибавляет 12345, то вам надо 12345 вычитать в дешифраторе. Побитовое исключающее ИЛИ обратно само себе, ведь если его применить 2 раза, то получится исходное число.

    С умножением все гораздо сложнее. Я предполагаю, что тип state - unsigned int. Если он знаковый, то умножение с переполнением - это undefined behavior вообще. В безнаковых целых умножение с переполнением есть просто умножение и взятие по модулую 2^32. Т.е вам нужно найти операцию, обратную умножению по модулю 2^32.

    Это будет умножение на обратное по модулю.

    Для его нахождения вам надо будет использовать расширенный алгоритм эвклида (в статье по ссылке выше оно расписано). Его можно или реализовать отдельно для нахождения обратных к 31663 (и другим множителям). Или можно его руками на бумажке прогнать.

    Отдельно вам надо разобратсья с отрицательным множителем. Вам надо найти положительный множитель, который будет давать точно такой же результат шифрования. Подсказка.

    Edit, только заметил в вопросе, что state - двубайтовый. Значит, все происходит по модулю 2^16.
    Ответ написан
    9 комментариев
  • Как перебрать все суммы массива?

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

    Перебирите все битовые маски (числа) от 0 до 2^n -1 (mask = 0; mask < (1 << n); ++mask).

    А внутри при подсчете суммы пройдитесь по всем позициям массива и, если i-ый бит установлен, прибавляйте текущее число. Проверить, что бит установлен можно сделав побитовое и (&) c 1 << i.

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

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

    Проверить, что что-то не так можно через векторное произведение последовательных сторон.

    Для всех 3 подряд идущих вершин a, b и c, то надо проверить, что (b-a)*(c-b) всегда дает одинаковый знак (или всегда <=0 или всегда >=0). Это векторное произведение.
    Формула в вашем случае будет (xb-xa)*(yc-yb)-(xc-xb)*(yb-ya).

    Еще можно построить выпуклую оболочку (convex hull).
    Вот расписан алгоритм, как ее построить по заданным точкам: https://e-maxx.ru/algo/convex_hull_graham

    Edit: Еще можно, вместо сортировки точек в выпуклую оболочку, игнорировать клики от пользователя, которые делают текущий многоугольник невыпуклым. Опять же, проверку невыпуколсти можно делать только для новых сторон: В последней, новой и первой точках.
    Ответ написан
    2 комментария
  • В чем моя ошибка в задаче?

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

    Но вот случай, когда достаточно одного числа вы неправильно разобрали. Почему вы ищите самое большое простое число? Какой вообще смысл смотреть, что в позиции ans-1 стоит c?

    А еще ваш код выводит 0 неверно иногда.

    Вы, может, задачу неправильно поняли? Надо сделать так, что бы все позиции, в которых символы отличные от c, не делились бы на хотя бы одно число в вашем ответе.
    Ответ написан
    1 комментарий
  • Как настроить сборку для линковки двух разных версий одной библиотеки?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Автоматический метод могу предложить только один: перезагрузите компьютер. Если не помогло, то придется искать ошибку в коде.
    Ответ написан
    8 комментариев
  • Как "нормально" перевести float в int?

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

    Edit: Видимо, проблема в том, что 0.9 нельзя идеально точно представить в float. На самом деле там хранится что-то вроде 0.8999999.... При домножении на 10 и округлении вниз вы получите 8, а не 9.

    Надо использовать округление к ближайшему - round.
    Ответ написан
    1 комментарий
  • Как расширить массив с++ (добавить элемент)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Используйте std::vector. Он автоматически расширяется и при этом работает быстро.
    Ответ написан
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Тут проблема не в том, что член класса char*, а в том, что запись идет в char*, и из-за strict aliasing правил - это может быть запись куда угодно, в том числе в &this. Кешировать пришлось бы любой член структуры, любого типа.

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

    Частично это можно решить кешированием, можно попробовать поменять типы кое где. Но делать это не стоит - это та самая преждевременная оптимизация, о которой писал Кнут. Лучше алгоритм хороший и структуры данных правильные в вашей программе выберите. А уже дальше, если профилирование покажет, что вот тут вот узкое место, то можно смотреть на ассемблерный код и думать, как убедить компилятор геренировать что-то более быстрое.
    Ответ написан
  • Как вывести на экран все значения элементов лежащих по одному ключу в std::map?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Нужно использовать multimap, а котором ключами будут фамилии. Тогда можно вывести все телефоны по фамилии пройдясь мо этому мапу с lower_bound до upper_bound. Похоже там, откуда вы списывали примерно такая идея и была. Иначе зачем вам два абсолютно одинаковых map в коде (surname_book есть точная копия phone_book)?
    Ответ написан
  • Как соеденить массив строк в одну строку и разделить пробелами?

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

    Если по условию задания вам надо делать все руками, то нужно выделить память, чтобы все поместилось, а дальше можно воспользоваться strcat_s, memcpy или вообще посимвольно копировать.
    Ответ написан
    Комментировать
  • Не правильно сортируется параллель под побочной диагональю. Что не так и что надо исправить?

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

    Вам должно сразу стать понятно, что в одной строчке написан полный, абсолютный, дисстилированный бред.
    Ответ написан
    5 комментариев
  • Как узнать сколько байт прочитал std::ifstream.read()?

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

    Там английским по белому написано:
    The number of characters successfully read and stored by this function can be accessed by calling member gcount.


    И даже пример внизу есть.
    Ответ написан
    Комментировать
  • Почему решение задачи неправильное?

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

    Оно, например, не работает на тесте s="abc" t="zzzzzcba". Ваша реализация скажет, что abc является подпоследовательностью, хотя на самом деле - нет.

    Еще хочется отдельно привлечь внимание к гениальности кода:
    if (is_sub)
            return true;
        else
            return false;


    Он кажется мне немного перемудренным.
    Ответ написан
    1 комментарий
  • Самомодифицирующийся код на c++ изменяющий значения переменой для нового запуска?

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

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

    В линуксе можно исполняемый файл редактировать, пока он запущен - поэтому там попроще. Чтобы бороться с sigkill стоит редактировать файл в самом начале после запуска.
    Ответ написан