РУҚА
Задания № 22, 23 · ЕГЭ

Поиск решения задачи Водолей по графу состояний

Как построить граф состояний и найти кратчайшую последовательность переливаний методом BFS
6 мин чтенияСложность: Обновлено 29 сентября 2026

Задачи «Водолей» удобно решать не перебором случайных последовательностей команд, а поиском по графу состояний. Каждая вершина графа описывает, сколько воды находится в каждом сосуде, а каждое ребро соответствует одному допустимому переливанию; поиск в ширину находит путь с минимальным числом переливаний.

Модель задачи: состояния и переходы

Перед построением графа нужно определить вместимости сосудов, их начальные объёмы и условие цели. Например, для сосудов вместимостью \(5\) и \(3\) литра состояние можно записывать парой \((x,y)\): \(x\) — количество воды в первом сосуде, \(y\) — во втором. Начальное состояние обозначим \(S_0\), а целевым назовём любое состояние, удовлетворяющее условию задачи.

Описание формата состояния и допустимых действий важно прочитать заранее: состояние сосудов задаёт вершины графа, а команды исполнителя Водолей задают переходы между ними. В некоторых задачах разрешены только переливания, в других можно также наполнить сосуд или вылить его содержимое.

D
Состояние

Состояние Водолея — набор объёмов воды во всех сосудах в данный момент. Для двух сосудов оно имеет вид \((x,y)\), где \(0\le x\le A\) и \(0\le y\le B\), а \(A\) и \(B\) — вместимости сосудов.

D
Граф состояний

Граф состояний — ориентированный граф, в котором вершины являются состояниями сосудов, а дуга \(u\to v\) существует, если из состояния \(u\) можно выполнить одну команду и получить состояние \(v\). Каждая дуга считается одной операцией.

\[V=\{(x,y)\mid 0\le x\le A,\ 0\le y\le B\}\]

Для двух сосудов число потенциальных состояний не превосходит \((A+1)(B+1)\), если вместимости выражены целыми литрами. Однако реально достижимых состояний может быть меньше. Например, при некоторых вместимостях сохраняется общий делитель, поэтому часть пар никогда не появится.

Как строятся переходы

Рассмотрим переливание из сосуда \(X\) вместимостью \(A\) в сосуд \(Y\) вместимостью \(B\). Если текущее состояние \((x,y)\), то из первого сосуда можно перелить объём \(d\), равный минимуму доступной воды и свободного места во втором сосуде.

\[d=\min(x, B-y)\]
\[(x,y)\longrightarrow(x-d, y+d)\]

Аналогично для переливания из \(Y\) в \(X\):

\[d=\min(y, A-x),\qquad (x,y)\longrightarrow(x+d, y-d)\]

Если разрешены дополнительные команды, для каждого состояния добавляются переходы наполнения и опустошения. Например, наполнить первый сосуд можно так: \((x,y)\to(A,y)\), а вылить его содержимое: \((x,y)\to(0,y)\). Все команды, которые не изменяют состояние, не добавляются: переход из вершины в саму себя не помогает найти более короткое решение.

T
Правило одного перехода

При переливании из одного сосуда в другой переливается максимально возможный объём: либо сосуд-источник опустошается, либо сосуд-приёмник заполняется. Поэтому после одной команды нельзя остановиться на произвольном промежуточном объёме, если такая остановка не разрешена условием.

xAyBпереливание
Переливание из сосуда вместимостью A в сосуд вместимостью B.
Проверь себя

В состоянии \((2,3)\) сосуды имеют вместимости \(5\) и \(4\) литра. Какое состояние получится после переливания из первого сосуда во второй?

Поиск кратчайшего решения

Все операции имеют одинаковую стоимость: одна команда — одно переливание или другое действие исполнителя. Поэтому используется минимальное число переливаний, а алгоритмически это поиск в ширину (BFS). Он просматривает сначала начальное состояние, затем все состояния на расстоянии \(1\), потом на расстоянии \(2\) и так далее.

T
Почему BFS даёт минимум

Если все рёбра графа имеют одинаковый вес \(1\), поиск в ширину впервые достигает вершины по пути минимальной длины. Следовательно, первый найденный путь от начального состояния до целевого содержит минимальное число операций.

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

Псевдокод
очередь := [начальное состояние]
посещено[начальное состояние] := истина
расстояние[начальное состояние] := 0
предок[начальное состояние] := нет

пока очередь не пуста:
    s := удалить из начала очереди
    если s — целевое состояние:
        восстановить путь по предкам
    для каждого состояния t, получаемого одной командой из s:
        если t не посещено:
            посещено[t] := истина
            расстояние[t] := расстояние[s] + 1
            предок[t] := s
            добавить t в конец очереди

если очередь пуста:
    решения нет

Множество посещённых состояний обязательно: один и тот же узел может быть получен разными последовательностями команд. Если добавлять его в очередь повторно, возникнут циклы и лишняя работа. Это связано с общей идеей обхода пространства состояний исполнителем.

!
Частые ошибки

Не перебирайте все последовательности фиксированной длины без защиты от повторов: число вариантов быстро растёт. Не отмечайте состояние посещённым только после извлечения из очереди — его могут несколько раз добавить в очередь. Не путайте длину пути с числом состояний: если начальное состояние уже целевое, ответ равен \(0\), хотя в пути записана одна вершина.

Разобранный пример: сосуды 5 и 3 литра

Пусть оба сосуда изначально пусты, разрешены наполнения, опустошения и переливания, а требуется получить ровно \(4\) литра в первом сосуде. Обозначим состояние как \((x,y)\), где вместимости равны \(5\) и \(3\).

№
Идея решения

Чтобы получить \(4\) литра в первом сосуде, можно несколько раз получать \(2\) литра во втором сосуде и переносить их в первый. Но BFS проверяет все варианты одновременно по числу команд и гарантирует, что найденный путь кратчайший.

1
Начинаем с пустых сосудов.
(0,0)
2
Наполняем второй сосуд.
\(\displaystyle (0,0)\to(0,3)\)
3
Переливаем из второго сосуда в первый; первый получает 3 литра.
\(\displaystyle (0,3)\to(3,0)\)
4
Снова наполняем второй сосуд.
\(\displaystyle (3,0)\to(3,3)\)
5
Переливаем во второй сосуд? Нет: переливаем из второго в первый. В первом свободны 2 литра, поэтому во втором остаётся 1 литр.
\(\displaystyle (3,3)\to(5,1)\)
6
Опустошаем первый сосуд.
\(\displaystyle (5,1)\to(0,1)\)
7
Переливаем оставшийся литр во второй сосуд.
\(\displaystyle (0,1)\to(1,0)\)
8
Наполняем второй сосуд.
\(\displaystyle (1,0)\to(1,3)\)
9
Переливаем из второго в первый: первый получает 3 литра и становится равен 4.
\(\displaystyle (1,3)\to(4,0)\)

Получена последовательность из \(8\) команд. В реальной задаче BFS не угадывает эту цепочку, а строит её автоматически: для каждого состояния рассматриваются все разрешённые команды, а при достижении цели сохраняются предки.

Показать восстановление пути решение
  1. Начать с целевого состояния \((4,0)\).
  2. Перейти к его предшественнику \((1,3)\).
  3. Продолжать переходы по массиву предков, пока не будет достигнуто \((0,0)\).
  4. Развернуть полученный список состояний. Разность соседних состояний показывает выполненную команду.

Оценка перебора и практический алгоритм

Если вместимости равны \(A\) и \(B\), число пар состояний не превосходит \((A+1)(B+1)\). Для каждой вершины проверяется постоянное число команд, поэтому время работы BFS имеет порядок \(O(AB)\), а память — также \(O(AB)\). Для трёх и более сосудов число состояний становится произведением \((A_1+1)(A_2+1)\cdots(A_n+1)\).

\[N\le\prod_{i=1}^{n}(A_i+1)\]

Перед программированием полезно составить таблицу переходов вручную для нескольких состояний. Это помогает проверить, не перепутаны ли вместимости, направление переливания и условие остановки. Если команды имеют разные стоимости, обычный BFS уже не подходит: тогда нужен другой алгоритм поиска кратчайшего пути.

Приём для экзамена

Сначала выпишите формат состояния, затем все типы команд, после этого найдите соседей начальной вершины. Если задача просит только минимальное число действий, достаточно хранить расстояния. Если требуется вывести последовательность, обязательно храните предка и команду, которой получен новый узел.

Q
Быстрый тест по теме

Быстрая проверка

~ 2 мин4 вопроса
Вопрос 1 / 4
Вопрос 1 из 4 · модель
Что является вершиной графа состояний?
Главное за минуту

Главное

  • Состояние Водолея записывается как набор объёмов воды в сосудах, например \((x,y)\).
  • Граф имеет состояния в качестве вершин, а допустимые команды — в качестве переходов.
  • При одинаковой стоимости операций кратчайшее решение ищется поиском в ширину.
  • Для каждого состояния нужно хранить посещённость, расстояние и, при необходимости, предка.
  • Число потенциальных состояний для двух сосудов не превосходит \((A+1)(B+1)\); повторные состояния не обрабатываются заново.