Задать вопрос
  • Не удается открыть семафор, в чем ошибка?

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

    Может, там, вполне NULL возвращается. И да, лучше HANDLE не сравнивать с nullptr. Это, все-таки, не указатель.
    Ответ написан
    1 комментарий
  • Почему вектор перемещения не поддается правилу треугольника при вычитании векторов?

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

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

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

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

    Вот как вы себе пердставляете перемещение int*?
    int* - это адрес в памяти. Число. Когда вы "перемещаете" img этого типа, вы перемещаете одно число. Из переменной img, в вектор.

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

    Да, указатели используются в перемещении. Вместо того, чтобы копировать буффер в новое место. можно просто переприсвоить указатель в новой структуре на указатель в старой. Именно так вы перемещаете указатель, вместо копирования данных по этому адресу. Вот чем перемещение отличается от копирования.

    Так, у вас в imgs вы не пихаете копию данных, а пихаете указатель.
    Ответ написан
    2 комментария
  • Как найти 7 неизвестных?

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

    Сходу очевидно, что x=y=a+b=c+d+k дает по нулям все левые части, что удовлетворяем всем неравенствам.

    Так что, берем x=y=a=c=1, b=d=k=0

    Плюс, можно менять 1 на что угодно. Можно распределять эту 1 между a и b, а так же между c, d и k. Бесконечно много решений.

    Похоже, тут проблема XY. Давайте вашу изначальную задачу - откуда вы эти неравенства взяли. Потому что их решение выглядит бесполезным. Вы что-то не то придумали, решили, что вам нужны эти неравнества, но это - тупик.
    Ответ написан
    4 комментария
  • Получение значения указателя в структуре которая является указателем?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В чем проблема? Если бы у вас в структуре было поле типа int, как бы вы получали значение этого поля? вот точно так же, только у вас тип не int, а char*

    struct Foo {
    char* data;
    };
    
    Foo* bar;
    char* pointer = bar->data;
    Ответ написан
    Комментировать
  • Где могла закрасться ошибка?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    В вашем рассуждении ошибка в том, что вы не домножаете условную вероятность 2/6 на вероятность условия. Вы же полную вероятность считатете а P(A) = P(A|B)*P(B)+P(A|!B)*P(!B). У вас P(A|B) = 0, как вы заметили - если они встретились в первом туре, то во втором уже не встретятся. Но все-равно надо 2/6 домножать на P(!B) - вероятность того, что они не встретились в первом туре. А это 1-1/7 = 6/7. В итоге получается все то же 2/6*6/7=2/7.

    Но рассуждения автора проще. Можно рассмотреть все независимые элементарные исходы "где в сетке оказался второй игрок". Их 7, они равновероятны по симметрии. Дальше надо домножить на вероятность, что они начиная так встретятся (выиграют свои матчи).
    Ответ написан
    4 комментария
  • Почему 3 секунд не хватает для выполнения кода?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    У вас решениe за O(n^3), ибо у вас там 2 вложенных цикла до n, а внутри еще и постоянно вызываются min/max, которые проходятся по всему массиву.

    Ограничения же в задаче n<10^5. С такими ограничениями максимум O(n log n) решение уложится в 3 секунды.

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

    Что можно сделать с входным массивом, чтобы можно было получать несколько самых маленьких элементов быстро? Помните, что вам надо уложиться в O(n log n).
    Ответ написан
    Комментировать
  • Как обрабатывать переполнение счетчиков и индексов?

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

    - определять переполнение и как-то его бросать исключение или завершать программу. Все операции идут с проверками.

    - Clamped типы. Максимальное значение типа считается бесконечностью. Прибавление к нему не меняет это значение. Переполнение выдаст это максимальное. Все операции с переменной, естественно, тоже сопровождаются проверками. Тут есть возможность потом какие-то выводы о значении счетчика потом даже делать. Вы будете видеть, что там больше или равно INT_MAX, но насколько больше - знать не будете.

    - Wraparound. Часто вам не важно абсолютное значение счетчика. Нужно лишь знать, какое из двух значений больше. При этом вы знаете, что сравниваемые значения не могут быть слишком большими. Тогда очень маленькое значение будет считаться больше очень большого. Два примерно одинаковых будут сравниваться как обычные числа. Так можно делать, например, с sequence number пакетов. Если вы получите пакет с номером 0x02 после покета с номером OxFFF1, Можно с спокойно считать, что это номер после переполнения. Ну не будет сеть задерживать перетасовывать 65 тысяч пакетов.
    Ответ написан
    1 комментарий
  • Как найти компоненты связности в графе в распределенной памяти?

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

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

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

    Более сложный вариант - когда у вас сразу запускаются все волны. Опять же, без лидера совсем сложно будет.
    Тут, наверно стоит сначала в каждом отдельном параграфе найти все компоненты связности отдельно. Это будут промежуточные варианты.

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

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

    Чтобы определить, что все закончилось, можно разбить процесс на фазы. В первой фазе все рассылают свои номера. Во второй фазе только те, у кого номера обновились. И т.д. Фаза на сервере начинается после сообщения от лидера. Каждый сервер отправляет на лидер сообщение, когда он закончил рассылать свои номера и были ли там вообще обновления. Сообщения надо делать по tcp с подтверждением. Когда лидер заметит, что никто никаких сообщений больше не рассылал в предыдущей фазе - все сошлось.
    Ответ написан
    1 комментарий
  • Как правильно подключить #include?

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

    Надо forward declaration расставить кое где. Чтобы не было зависимости от порядка include в файлах, стоит, наверно, расставить их в обоих файлах:
    class c_image;
    class c_window {
    // ...
    }


    И для красоты стоит image.hpp включать не в window.hpp, а window.cc. Ну и для второго класса аналогично сделать.

    Но лучше иерархию классов перетряхнуть. Такие циклические зависимости - это плохо. Надо использовать какой-то базовый класс с общим интерфейсом. Тогда и window и image будут принимать вот этот вот базовый интерфейс, а не конкретный тип.

    Edit: Да, ошибка возникает потому, что в каком-то cc файле сначала вставился image.hpp, из которого вставился window.hpp (внутренний image.hpp в нем не вставляется из-за pragma once. Иначе бы была бесконечная рекурсия). В итоге у вас в .cc файле сначала идет определение класса window, и только потом класса image.
    Ответ написан
    Комментировать
  • Какая обёртка позволяет разыменовывать без неопределённого поведения?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну просто проверяйте в operator*: если nullptr, то бросайте исключение.
    Ответ написан
    2 комментария
  • Издержки полиморфизма или неправильный дизайн?

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

    В хорошем дизайне у вас какая-нибудь функция print будет. Которая будет соответствующее число красиво, в соответствии с типом, выводить. Или рисовать на экране что-то, или считать что-то.

    Если же вы действительно хотите брать вот такие совершенно разные по смыслу значения у разных наследников, то, да, в интерфейсе должны быть все функции. Можно в интерфейсе их определить с ассертами и переопределить только в нужных наследниках.
    Ответ написан
    1 комментарий
  • В чём ошибка вычисления бесконечно убывающей прогрессии с точностью до эпсилон?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Целочисленное переполнение при умножении i на i+1. Замените на, скажем prog += 1/((double)i*(i+1));, должно сработать.

    При i порядка 50000 результат перемножения не влезает в int. А у вас там 6697830 операций. В результате используются отрицательные или слишком маленькие неправильные значения i для вычисления слагаемых после 50000, и результат вообще не правильный.

    Ну и, кстати, логика решения у вас неправильная. Надо не с конечным значением сравнивать, а останавливаться, когда следующее слагаемое становится слишком маленьким.
    Ответ написан
    5 комментариев
  • Откуда взялся const?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    const char* взялся вот отсюда: "Hello world". Это строковая константа в коде. Ее программа менять никак не может. Компилятор ее засовывает в read only секцию исполняемого файла.
    Ответ написан
    Комментировать
  • C выдаёт ошибку при попытке сравнить 2 int?

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

    У вас там Undefined Behavior и, очевидно, проблемы работы с памятью. Ошибку вы замечаете не там, где она, собственно, происходит.

    Сразу вижу проблему вот тут:
    strcat(result, alph[mod]);

    Тут вы приписываете строку с адресом alph[mod] к строке по адресу result. Обратите внимание, не строку, начинающуюся с позиции mod в массиве alph, а строку с адресом вроде кода символа 'F'.

    Ну и, вряд ли вы хотите часть строки alph скопировать в result. Плюс у вас в alph[] нет места под терминирущий 0, поэтому strcat вызовет переполнение буфера. Вам там надо дописывать один символ в конец result. Библиотечных функций именно для этого нет. Заведите счетчик количества символов в ответе и тупо переписывайте значение result[cnt].
    Ответ написан
    2 комментария
  • Тонкости Компиляторов. Почему в классах с++ не требуется объявление функции до вызова?

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

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

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

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

    Так, если вершина "+", то скобки ставить вообще не надо. Если вершина "*", то надо ставить скобки вокруг ребенка, если там операция "+" или "-". Если вершина "-", то надо ставить скобки справа, если там "+" или "-". Если вершина "/", то надо ставить скобки вокруг левого сына, если там "+" или "-". Вокруг правого сына скобки надо ставить если не число. Подумайте аккуратно, может я какие-то правила упустил.

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

    Парсинг - очень заезженная тема. Гуглите. Самый простой алгоритм - квадртатичный - проходитесь по строке и ищите самую левую операцию с самым большим приоритетом вне скобок (ведя счетчик открытых скобок). Если такой нет, то можно опустить скобки по краям. Если их нет, то это число (или перменная). Если нашли операцию, то рекурсивно разбирайте две подстроки слева и справа.
    Ответ написан
    5 комментариев
  • Почему в С++ не работают 2 цикла for?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    for(; i < n; i++) Ничего глаз не режет? Зачем там точка с запятой после скобочки?
    Ответ написан
    Комментировать
  • Кормен или Кнут?

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