Задача про заборы

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

Ширина всех участков одинакова и равна 1.

Входные данные (поступают в стандартный поток ввода)

На вход вашей программе подаётся одна строка, содержащая массив целых чисел length, где length[i] - длина i-ого забора. Иными словами i-ый элемент массива задаёт забор в виде отрезка от (i, 0) до (i, length[i]), где 0 - это дорога.

Причём 0 ≤ length[i] ≤ 10 000, а количество заборов n удовлетворяет условию 2 ≤ n ≤ 100 000.

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

Выходные данные (ожидаются в стандартном потоке вывода)

Одно целое число, максимальная площадь образованного участка.

Пример 1

Ввод:

2 4 3 2 1 4 1

Вывод:

16

В первом примере участок наибольшей площади образуется между двумя заборами длины 4.

Пример 2

Ввод:

1 2

Вывод:

1

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

Мой код:

line = input()
length = [int(item) for item in line.split()]
max_area = 0
if length[0] > 0 and length[1] > 0:
    max_area = 1
for left in range(0, len(length) - 1):
    for right in range(left + 1, min(left + 1 + length[left], len(length))):
        min_length = min(length[left], length[right])
        width = right - left
        if min_length == width:
            max_area = max(max_area, min_length * width)
print(max_area)

Тесты пройдены. Но ответ неправильный. Вывод программы не совпал с ожидаемым. Что тут не так?


Ответы (2 шт):

Автор решения: Stanislav Volodarskiy

Ваша программа не всегда считает верно. Например, для ввода 100, 100 она вернёт единицу, хотя верный ответ – 100.

Я подозреваю этот кусок: if min_length == width:. Зачем он нужен?

Если условие удалить, пример выше начинает считаться верно. Следующий пример: 2 1 1 2. Ответ программы 2, верный ответ 6.

На этот раз под подозрением min(left + 1 + length[left], len(length)). Зачем нужен первый аргумент min?

Если вместо min подставить его второй аргумент, программа начинает считать верно.

В программе можно ещё кое-что поправить и упростить, но считает она правильно, только медленно. Хотя это тема для отдельного вопроса.

→ Ссылка
Автор решения: Leonid

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

Код на JS.

function findMaxArea(input_arr){
    let max_area = 0;
  
    for(let i=0; i < input_arr.length-1; i++){
        for(let j=i+1; j < input_arr.length; j++){
            max_area = Math.max(max_area, (j-i)*Math.min(input_arr[i], input_arr[j]));
        }
    }
  
    return max_area;
}

console.log(findMaxArea([1,2]));
console.log(findMaxArea([2,4,3,2,1,4,1]));

Более рациональная версия. Идем от обоих концов массива одновременно. Начальная наибольшая площадь: произведение минимального из длин по концам и длины массива - 1. Ищем больший вариант сдвигаясь с концов к середине до сближения левого и правого концов.

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

function findMaxArea(arr) {
  let l = 0;
  let r = arr.length - 1;

  let max_area = Math.min(arr[l], arr[r]) * (r - l);

  let longest_left = arr[l];
  let longest_right = arr[r];
  let to_right = longest_left <= longest_right;

  while (r - l > 1) {
    if (to_right) {
      l++;
      if (arr[l] <= longest_left) {
        continue;
      } else {
        longest_left = arr[l];
        if (longest_left > longest_right) {
          to_right = false;
        }
      }
    } else {
      r--;
      if (arr[r] <= longest_right) {
        continue;
      } else {
        longest_right = arr[r];
        if (longest_right > longest_left) {
          to_right = true;
        }
      }
    }
    max_area = Math.max(max_area, Math.min(arr[l], arr[r]) * (r - l));
  }

  return max_area;
}

console.log(findMaxArea([1, 2]));
console.log(findMaxArea([2, 4, 3, 2, 1, 4, 1]));

→ Ссылка