Задача по олимпиадному программированию

Наткнулся на одну задачу, я ее точно решить не смогу, но если кто-то ее решит, то был бы рад прийти в восторг от решения :)

Задача, как по мне, довольно сложная

Прочитал на одном форуме, что это нужно решать с помощью волнового обхода


В поисках сокровищ известный археолог попал в огромную сеть двумерных пещер. Он вспомнил, что в университете как раз делал дипломную работу по этой местности: руками подсчитывал количество сталактитов, сталагмитов и сталагнатов и записывал всё это в рабочую тетрадь. Да, ошибиться легко. Приходилось проверять себя несколько раз. Теперь же у него с собой есть портативный сканер местности, который переводит всё в матрицу из 0 и 1. Только вот незадача, там нет возможности узнать количество объектов на карте. Для знаменитого археолога нет непреодолимых препятствий, а проверить свои студенческие расчеты очень хочется.

Нужно реализовать метод scan, который принимает на вход карту – матрицу NxM, состоящую только из 1 (каменная порода) и 0 (пустое пространство). Матрица – это 2D карта пещеры, вид сбоку, аля платформер.

Пример карты:

[  
  [1, 1, 0, 0, 0, 1, 0, 1, 1],  
  [1, 1, 0, 1, 0, 1, 0, 0, 0],  
  [0, 1, 0, 1, 0, 0, 0, 1, 1]  
]

Формат вывода

Метод scan возвращает объект с количеством каждого типа образования {ceil: 0, floor: 0, both: 0}

  • Если образование свисает с потолка и не касается пола – ceil
  • Если образование растет от пола и не касается потолка – floor
  • Если образование свисает с потолка и при этом еще и касается пола – both Результат вывода на примере карты выше: {ceil: 2, floor: 2, both: 1}

Вот как стоило рассматривать массив, чтобы получить такой результат:

введите сюда описание изображения

Примечания

У одного образования может быть несколько точек касания.

Пример 1:

[
  [1, 0, 1],
  [1, 1, 1],
  [0, 0, 0]
]

Результат: {ceil: 1, floor: 0, both: 0}

Пример 2:

[  
  [1, 0, 1],  
  [1, 1, 1],  
  [0, 0, 1]  
]

Результат: {ceil: 0, floor: 0, both: 1}

Считаем, что по диагонали образования не пересекаются:

[  
  [1, 0, 1],  
  [0, 1, 0],  
]

Результат: {ceil: 2, floor: 1, both: 0}



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

Автор решения: Anton Shchyrov

Ну так и используйте волновой алгоритм

const data = [
[  
  [1, 1, 0, 0, 0, 1, 0, 1, 1],  
  [1, 1, 0, 1, 0, 1, 0, 0, 0],  
  [0, 1, 0, 1, 0, 0, 0, 1, 1]  
],
[
  [1, 0, 1],
  [1, 1, 1],
  [0, 0, 0]
],
[  
  [1, 0, 1],  
  [1, 1, 1],  
  [0, 0, 1]  
],
[  
  [1, 0, 1],  
  [0, 1, 0],  
]
];

function buildPath(map, x, y, res) {
  // Если находимся за границей массива или
  // точку не нужно обрабатывать, то выходим
  if (
    y < 0 || y >= map.length ||
    x < 0 || x >= map[y].length ||
    map[y][x] !== 1
  )
    return;

  // Если на потолке
  if (y === 0)
    res.ceil = true;
  // Если на полу
  if (y === map.length - 1)
    res.floor = true;

  // Точку обработали
  map[y][x] = -1;

  // Проверяем соседние точки
  buildPath(map, x, y - 1, res);
  buildPath(map, x - 1, y, res);
  buildPath(map, x + 1, y, res);
  buildPath(map, x, y + 1, res);
}

function parse(map) {
  const res = {
    ceil: 0,
    floor: 0,
    both: 0
  };
  for (let i = 0; i < map[0].length; i++) {
    let testObj = {
      ceil: false,
      floor: false
    };
    // проверяем точку на потолке
    buildPath(map, i, 0, testObj);
    if (testObj.ceil) {  // если было касание потолка
      if (testObj.floor)  // и было касание пола
        res.both++;
      else
        res.ceil++;
    }
    
    testObj = {
      ceil: false,
      floor: false
    };
    // проверяем точку на полу
    buildPath(map, i, map.length - 1, testObj);
    if (testObj.floor) {  // если было касание пола
      if (testObj.ceil)  // и было касание потолка
        res.both++;
      else
        res.floor++;
    }
  }
  return res;
}

for (let i = 0; i < data.length; i++)
  console.log(parse(data[i]));

→ Ссылка