Algoritmy

Три пирата делят свою добычу, в которую входят предметов разной ценности. Получится у вас помочь разделить добычу поровну?

  • Входные данные: Первая строка содержит целое число . Вторая строка содержит целые числа , разделённые пробелами.
  • Выходные данные: Вывести 1, если можно разделить на три поднабора с одинаковыми суммами; в противном случае — вывести 0.
  • Ограничения: , для всех .

Пример 1

Ввод

Вывод

4
3 3 3 3

0

Пример 2

Ввод

Вывод

1
30

0

Пример 3

Ввод

Вывод

13
1 2 3 4 5 5 7 7 8 10 12 19 25

1

  • .

Рассмотрим решение задачи. Обозначим как . Разделить набор из предметов на три части возможно, только если их общая ценность делится на три. То есть , где — это целое число. Так, нам необходимо разделить чисел на три части, где сумма чисел в каждой части равна . Одна из этих частей содержит -й трофей (с ценностью ). Если мы его уберём, то получим разделение первых трофеев на три части таким образом, что ценность двух из них будет равна , а сумма оставшейся части — .

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

💡 Остановитесь и подумайте:
Учитывая первые пять предметов, . Найдите все значения , равные .

💡 Остановитесь и подумайте:
Представьте, что вы уже составили двоичный двумерный массив для всевозможных значений и . Сможете ли вы использовать этот массив, чтобы составить массив ?

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

  • -й предмет принадлежит первой части. Тогда . Убрав его из первой части, мы разделим первые чисел на три части так, что сумма первых двух частей составит и , то есть .
  • -й предмет принадлежит второй части. Как и в предыдущем случае, и .
  • -й предмет принадлежит третьей части. Тогда .

Так, значение можно вычислить, посмотрев на

Базовый случай для этого рекуррентного соотношения: и , если .

Split(v[1],…,v[n]):
    if v[1] + … + v[n] не делится целочисленно на 3:
        return false
    V = (v[1] + … + v[n]) / 3
    split = ... // массив размера (n+1) × (V+1) × (V+1)
    // заполнить массив split значениями false
    split[0][0][0] = true
    for i from 1 to n:
        for s1 from 0 to V:
            for s2 from 0 to V:
                split[i][s1][s2] = split[i−1][s1][s2]
                if s1 >= v[i]:
                    split[i][s1][s2] = split[i][s1][s2] OR split[i - 1][s1 - v[i]][s2]
                if s2 >= v[i]:
                    split[i][s1][s2] = split[i][s1][s2] OR split[i - 1][s1][s2 - v[i]]
    return split[n][V][V]

Время выполнения составляет .

Отмечайте параграфы как прочитанные чтобы видеть свой прогресс обучения

Вступайте в сообщество хендбука

Здесь можно найти единомышленников, экспертов и просто интересных собеседников. А ещё — получить помощь или поделиться знаниями.
Вступить
Сообщить об ошибке
Предыдущий параграф8.6. Задача о рюкзаке
Следующий параграф8.8. Задача «Расставить скобки»