• Как исправить ошибку сборки проекта, при подключении sdl?

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Нет. Распишите формулы, они будут разные. В прогрессии каждый раз добавляется степень коэффициента q. В проценте происходит домножение на (1+q):
    A+Aq+Aq^2+Aq^3+...
    A+Aq+(Aq+Aq^2)+(Aq+2*Aq^2+Aq^3)+...
    Ответ написан
    Комментировать
  • Как называется матрица возможных состояний объекта?

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы наткнулись на важное свойство ассимптотического анализа. O(n^2) -означает, что на достаточно больших n, время работы будет примерно n^2 с точностью до константы. Эта самая константа может быть хоть 0.5, хоть 10000000.

    Сравните 2 алгоритма:
    // n(n-1)/2 инкремента.
    for(i = 0; i < n; ++i){
      for (j = i+1; j < n; j++) {
        cnt1++;
      }
    }
    // n^2 инкремента.
    for(i = 0; i < n; ++i){
      for (j =0; j < n; j++) {
        cnt2++;
      }
    }


    Оба алгоритма имеют O(n^2) сложность, но один делает примерно в 2 раза меньше операций.

    Суть в том, что хоть алгоритмы и работают с одинаковой ассимптотикой, они могут работать разное время! Особые странности могут быть при маленьких n. O(n log n) алгоритм часто может быть медленнее O(n^2) алгоритма. Поэтому все настоящие реализации сортировок для маленьких массивов запускают более тупые квадратичные алгоритмы.

    Если же вы хотите показать только ассимптотику, то возьмите n побольше, и тогда эти 30% будут незаметны по сравнению с десятикратным замедлением O(n^2) относительно O(n log n). Или нормируйте ваши сортировки. Искуственно ускорьте одни алгоритмы и замедлите другие, чтобы получить именно тот результат, который вы хотите. Но это как-то нечестно что ли. Если же вы все-таки хотите именно этого, назначьте каждой сортировке время C\*n^2 или С\*n\*log n миллисекунд. Прогоните алгоритмы сортировки без визуализации, подсчитайте, сколько операций замедления вы бы сделали (тот же самый код, что у вас, только вместо usleep() делайте sleep_count++). В конце подсчитайте коэффициент замедления - сколько каждый usleep должен спать, чтобы суммарно sleep_count их спал заданное время. И запускайте каждую сортировку уже с подсчитанными параметрами для usleep.
    Ответ написан
    Комментировать
  • Почему нельзя возвращать объект по значению в non-const &?

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

    По поводу ссылки. Результат работы функции в вашем случае - prvalue

    там же по ссылке написано:
    An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.

    An rvalue may be used to initialize an rvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.


    Т.е. стандартом запрещено инициализировать не const ссылку через prvalue.

    Почему это сделано? Потому что эти самые prvalue/rvalue по сути являются временными объектами. У них нельзя взять адрес, у них нет имени, компилятор может засунуть их куда угодно и уничтожить сразу за текущим выражением.

    Если бы можно было делать ссылку на эти временные объекты и как-то их менять потом, это бы усложняло анализ и возможность некоторых оптимизаций. Как, например, RVO в вашем вопросе. Пришлось бы создавать временную переменную в main для хранения результата, потому что функция память под результат не выделяет. Поэтому в стандарте C++ этого нет.

    Потом, когда в С++11 ввели rvalue ссылки и перелопатили категории значений - разрешили инициализировать rvalue ссылки через prvalue.

    Поэтому работают
    const int& r1 = f();
    int&& r2 = f();
    Ответ написан
    1 комментарий
  • Как в массиве хранить указатели на объекты разных типов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Если все эти типы унаследованны от одного и того же класса, то можно хранить указатели на базовый класс.
    Ответ написан
    3 комментария
  • Как решить задачу, используя одну формулу и не успользуя if, else, elif?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Бинарный поиск.
    Можно реализовать без if-ов вообще.
    Суть в том, что у вас есть текущий отрезок. Находите середину, спрашиваете про нее. Получаете ответ R = 0 или 1. Потом прибавляете половину отрезка к левой границе, умноженную на R и вычитаете ее из правой границы, умноженную на 1-R. Таким образом сдвинется только одна граница. Остается вопрос, что делать с выходом из цикла. Там же внутри if запрятан.

    Можно или скопировать код 7 раз (2^7 > 100), или иметь бесконечный цикл, который будет сравнивать границы и вызвать одну из двух функций в массиве на 2 элемента. Одна из функций выведет ответ и завершит работу программы через exit. Вторая - не будет делать ничего.
    Ответ написан
    Комментировать
  • Как исправить ошибку EXC_BAD_ACCESS (code=1, address=0x0)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы "создаете" класс sf::RectangleShape через malloc в составе временных массивов pq, qr. Он оказывается заполнен мусором. Нарушены какие-то его внутренние инварианты. Может быть куча проблем: начиная от того, что там переопределен оператор присванивания, который должен что-то где-то почистить, заканчивая тем, что таблица виртуальных методов у класса будет испорчена. Любая попытка сделать что угодно с таким экземпляром класса - скорее всего неопределенное поведение.

    Если уж вы используете классы из C++, то выделять память надо через new[], а не malloc. Тогда экземпляр класса создасться нормально и конструктор вызовется.

    Можно было бы подумать, что memmove решил бы вашу проблему - но, опять же, при этом нарушаются внутренние инварианты. Какой-нибудь unique_ptr внутри будет уже не уникальным. Такие операции работы с памятью можно делать только для POD (Plain old data) - структур состоящих из структур, массивов и базовых типов.

    Или, еще лучше использовать vector для временных массивов. Тогда вам не придется заботиться об освобождении памяти. Еще, вместо копирования можно использовать std::move, может работать бысрее, если эти sf классы имеют более эффективные операторы перемещения.
    Ответ написан
    1 комментарий
  • Как вынести определение конструктора шаблонного класса(вариативного) вне него?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Надо так:
    template<typename ...Args>
    UniformBuffer<Args...>::UniformBuffer(Args... arg)
    { 
    //код
    }


    У вас шаблоном является сам класс, а не его методы.
    Ответ написан
    2 комментария
  • Сортировка точек против часовой стрелки?

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

    Вот только угол идет от -pi до pi, а не от 0 до 2pi. Если вы хотите, чтобы первая точка была {1, 0}, то надо к отрицательным углам прибавлять 2pi перед сравнением.

    Это будет работать, но не очень оптимально. Atan - медленная штука. Можно сравнивать знаки координат сначала.

    Если одна точка с положительным y, а другая с отрицательным - положительная идет раньше. Если одна из точек имеет y=0 или знаки одинаковые - сравнивайте знаки по x. Выше и ниже оси OX - сравнения должны давать разные выводы (выше оси OX, положительные x идут раньше отрицательных, ниже оси OX - наоборот).

    Или для каждой точки в зависимости от двух знаков координат надо назначить квадрант от 1 до 4. И сначала сортировать по ним.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Заведите char массивы какой-то достаточной длины. Читайте через gets_s. Сравнивайте строки через strcmp.
    Ответ написан
    Комментировать
  • Как рендерить dx3d11 в dx3d9?

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Координаты центра ромба {x,y} - {130/2*(x-y), 84/2*(x+y)}

    Эту формулу можно вывести, например, не зная вообще ничего. Просто проведите все вертикальные линии через все центры ромбов. Какие ромбы лежат на одной прямой? Немного посмотрев, можно заметить, что это те, у которых разность координат одинаковая. Аналогично, проведя горизонтальные линии - можно заметить, что на одной горизонтали лежат ромбы с равной суммой координат.

    Далее надо найти координаты нескольких прямых и можно вывести формулу.

    Второй вариант - через геометрию векторов (это линейная алгебра, или еще нет - как это в школе-то называется вообще?). Нарисуйте вектор из ромба {0,0} в ромбы {1,0} и {0,1}. Ясно, что ромб с координатами {x,y} можно получить сложив x раз первый вектор и y раз второй. Подставляя координаты получите ту же формулу.
    Ответ написан
    Комментировать
  • Как найти слово, гарантированно отсутствующее в наборе?

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

    Если вы видите, что у вас однобуквенных слов меньше, чем букв в алфавите - то можно выдать однобуквенное слово. Иначе, если двух-буквенных слов меньше |alphabet|^2, то можно выдать двубуквенное слово. И так далее. Вот нашли вы минимальную длину.

    Чтобы найти и само слово, заведите битмап размером со сколько у вас слов. Потом пройдитесь по словам и если слово нужной длины, поставьте 1 в битмапе с номером равным строке, если ее интерпретировать как число в |alphabet|-ой системе счисления (самый младший символ равен цифре 0). Если число переваливает за размер битмапы, то можно текущую строку проигнорировать. Потом найдите любой 0 бит в битмапе. Его номер переведите назад в |alphabet| систему счисления.

    Пример. Алфавит - {a,b}. Слова: "a", "b", "aa", "ab", "bb".

    Мы видим 2 однобуквенных слова. Никак. 3 двухбуквенных, но 3 < 2^2 - значит можно выдать двубуквенную строку.

    У нас 2 символа в алфавите, интерпретируем a=0, b=1. "aa" = 0, "ab" = 1, "bb" =3. В битмапе останется пустым индекс 2. Это 10 в двоичной системе или "ba" в строках - это и есть ответ. Да еще и лексикографически минимальный.

    Если слова могут повторятся, то можно чуть изменить решение: точно также перенумеруйте все возможные слова в вашем алфавите. Сначала будут однобуквенные, потом двубуквенные и т.д. При переводе строки в индекс - также переводите из |alphabet|-ичной системы счисления. Но для слова из l символов прибавляйте смещение |alphabet|^(l-1)+|alphabet|^(l-2)+... |alphabet|^1. Точно так же, если в процессе вычисления видно, что индекс не поместится в битмапу (больше количества строк), то можно забить на эту строку. Поэтому же можно сразу пропускать слишком длинные слова.

    Опять же, помечайте бит в битмапе. Потом найдите первый нулевой бит. И назад преобразуйте в строку - сначала найдите смещение (суммируйте степени |alphabet|, пока они не перевалят за текущий индекс). Так вы поймете, сколько символов у вас в строке. Вычтите смещение и переводите индекс в |alphabet|-ичную систему счисления.

    Этот вариант в среднем может работать чуть дольше, но все так же очень быстро.

    Еще, оба эти варианта самые экономные по памяти.
    Ответ написан
  • Как создать новый поток c++?

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

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

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

    Если очень хочется лямбду, то чисто теоретически, ваши переменные можно засунуть в глобальные переменные. И тогда лямбда не будет ничего захватывать. Но это дичайший говнокод - так делать не надо.
    Ответ написан
    1 комментарий
  • Почему квадрантовое дерево медленнее брутфорса?

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

    Еще, ваше дерево, если точки лежат кучно, создает очень много пустых вершин. Представьте, что все точки лежат очень близко к левому нижнему углу. Вы разобъете квадрат на 4 части, но 3 из них пусты. Вы повторяете эту операцию, пока квадраты не станут совсем маленькими и не разобьют точки на несколько групп.
    Первая оптимизация - не добавлять точки по одной, а обрабатывать их группой. Если в текущей вершине точек слишком много - надо найти медианную точку по горизонтали, а внутри каждой группы медианную по вертикали. И будут у вас 4 прямоугольника на месте изначального, но они не будут выравнены как 4 четверти квадрата. Но зато будут всегда делить пополам.

    Вторая оптимизация - если вы видите, что bounding rect текущей вершины лежит целиком в запросе - надо просто вернуть все точки.

    Но есть другая структура, которая будет работать лучше в вашем примере, хоть и занимать в log n больше памяти.

    Вам нужно дерево отрезков бинарных деревьев поиска (можно использовать std::set).
    Заведите дерево отрезков по OX, где каждая вершина будет упорядоченное по OY set всех точек попадающих в данный отрезок по X.

    При запросе вы разбиваете отрезок по X запроса на Log n отрезков-вершин в дереве отрезков (это те вершыны, которые надо взять в запрос по ссылке выше) Далее в каждом из этих Logn сетов можно через lower_boundary и upper_boundary получить итераторы начала и конца всех точек в вашем запросе.

    Т.е вы можете получить все точки за O(log n). Правда, какая-то обработка их уже будет O(n) в худшем случае - вся ассимптотика портиться. Но если вам нужно только их количество, то вы можете найти расстояния между двумя итераторами за константу и не надо точки никуда копировать в вектор.

    Но даже если вам надо будет точки все в прямоугольнике обойти, то тут тоже можно ускорить немного - вы не копируйте точки в vector. Вы так и возвращайте вектор пар итераторв начала и конца в разных set-ах. И, если вам надо будет обойти точки - обходите двумя вложенными циклами - один по вектору пар итераторов, и второй по самим итераторам.

    Еще, оптимизация, если у вас lower_bound оказался равен upper_bound, то не надо эту пару итераторов (пустой интервал) класть в массив ответа.

    Еще один бонус этой структуры, что можно быстро удалять/добавлять/менять точки и все остается балансированным. Но, в отличии от kd-дерева, оно занимает в log n раз больше памяти и операция поиска всегда занимает O(log n + ответ), что может быть чуть медленее лучшего случая kd дерева, где вы можете сразу же закончить поиск, если очевидно, что в ответе ничего нет. Зато в худшем случае будет работать быстрее.
    Ответ написан
    Комментировать
  • Найти номер первого и последнего вхождения элемента в масссив?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Что у вас там за цикл по k после вызова бинприска? Именно он и тормозит делая вашу программу работать за nm вместо m log n.

    И да - используйте lower_bound и upper_bound. Это в точности то, что вам нужно.
    Ответ написан
    Комментировать
  • Как вывести формулу?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Сначала заменой x=x'+x0, y=y'+y0 можно убрать коэффициенты D и E и считать, что центр лежит в точке {0, 0}.

    Дальше надо подобрать такой угол поворота, что коэффициент при xy станет нулем. Тогда останется что-то вроде A'x^2+C'y^2 + F' = 0 - а значит эллипс выравнен вдоль осей и это был искомый угол.

    Подставляя формулы поворота системы координат x=x' cosa-y' sina и y=x' sina + y' cosa и приводя слагаемые можно составить уравнение на этот самый коэффициент перед xy. Он будет озависить только от A,B,C и sina, cosa. Далее это тригонометрическое уравнение надо причесать и решить. Вам придется воспользоваться вот этой формулой для котангенса двойного угла: maxresdefault.jpg.

    У вас будет уравнение с косинусами, синусами. Его можно элементарно привести к тангенсу. Далее применяете эту формулу и получаете ответ.
    Ответ написан
    Комментировать
  • Как удалить поддерево полностью?

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

    Этот код переписывает значение указателя node, который является аргументом функции, переданным по значению. Фактически, вы затираете локальную переменную.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    System - это глобальный экземпляр класса, который содержит член out, у которого есть метод println.
    class SystemType {
    public:
      class Out {
          public: void println() {
              cout << "haha";
          }   
      } out;
    } System;
    Ответ написан
    Комментировать