← Все вопросы

Поток переполняет int — где именно копится переполнение и почему недостаточно long long только на ответе?

Задан 24 месяца назад925 просмотров2 ответа
9

В задаче пропускные способности до $10^9$, рёбер до $10^5$. Сделал тип ответа long long, но всё равно ловлю переполнение / неправильный поток. Подозреваю, что int где-то внутри. Где именно в потоковом коде переполнение опасно и что менять на long long?

2 ответа

14
✓ Принятый ответ — помог автору

Замены типа только у итогового flow недостаточно — переполнение прячется внутри обновлений остаточной сети. Опасные места:

  1. Поле cap в структуре ребра. Если суммарный поток через ребро (или сумма параллельных capacity) превышает $2^{31}-1$, само поле cap переполнится. При пропускных до $10^9$ и сложении на обратных рёбрах это легко. → long long cap.
  2. Переменная push (минимум по пути). Она берёт минимум остаточных, но участвует в flow += push и в cap -= push. Если push объявлена int, а складываете в long long flow — само сложение ок, но cap -= push при int cap сломается. → делайте всю арифметику остатков в long long.
  3. Инициализация INT_MAX как «бесконечность» для push/dist. При суммировании нескольких рёбер с большими cap или в MCMF (dist[v] + e.cost) INT_MAX переполнится. Берите LLONG_MAX и осторожно с переполнением при сложении (не складывайте LLONG_MAX + cost).

Правило: в потоке делайте cap, flow, push, бесконечности и (в MCMF) стоимости/расстояния все long long. Цена — копейки по памяти, а баг ловится крайне тяжело, потому что на маленьких тестах не проявляется.

struct Edge { int to; long long cap; };
long long push = LLONG_MAX;          // не INT_MAX
for(...) push = min(push, e[id].cap);

Для Менгера/паросочетания (единичные cap) int достаточно — там переполнения нет. Опасность именно в задачах с большими пропускными.

5

Добавлю про MCMF отдельно — там переполнение коварнее. Стоимость пути копится как cost += push * dist[t]. Если push до $10^9$, а dist[t] до $10^9$, то произведение до $10^{18}$ — на грани long long, а сумма по многим путям может и вылезти. Считайте максимум суммарной стоимости заранее и при сомнении используйте __int128 для аккумулятора стоимости. Также при сравнении dist[v] + e.cost < dist[e.to] следите, чтобы dist[v] не был «бесконечностью» — иначе сложение LLONG_MAX + cost переполнится и даст ложное обновление. Защита: пропускать релаксацию, если dist[v] == LLONG_MAX.

Ваш ответ

Войдите, чтобы ответить на вопрос.