Найти все лужи на квадрате (алгоритм)

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

ширина высота

ширина * высота неотрицательные числа, описывающие высоту каждого каменного камня над уровнем травы.

Объем воды из луж.

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

. — нет лужи

# — лужа

Входные данные:

8 8
0 0 0 0 0 1 0 0
0 1 1 1 0 1 0 0
0 1 0 2 1 2 4 5
0 1 1 2 0 2 4 5
0 3 3 3 3 3 3 4
0 3 0 1 2 0 3 4
0 3 3 3 3 3 3 0
0 0 0 0 0 0 0 0

Выход:

11
........
........
..#.....
....#...
........
..####..
........
........

Входные данные:

16 16
8 0 1 0 0 0 0 2 2 4 3 4 5 0 0 2
6 2 0 5 2 0 0 2 0 1 0 3 1 2 1 2
7 2 5 4 5 2 2 1 3 6 2 0 8 0 3 2
2 5 3 3 0 1 0 3 3 0 2 0 3 0 1 1
1 0 1 4 1 1 2 0 3 1 1 0 1 1 2 0
2 6 2 0 0 3 5 5 4 3 0 4 2 2 2 1
4 2 0 0 0 1 1 2 1 2 1 0 4 0 5 1
2 0 2 0 5 0 1 1 2 0 7 5 1 0 4 3
13 6 6 0 10 8 10 5 17 6 4 0 12 5 7 6
7 3 0 2 5 3 8 0 3 6 1 4 2 3 0 3
8 0 6 1 2 2 6 3 7 6 4 0 1 4 2 1
3 5 3 0 0 4 4 1 4 0 3 2 0 0 1 0
13 3 6 0 7 5 3 2 21 8 13 3 5 0 13 7
3 5 6 2 2 2 0 2 5 0 7 0 1 3 7 5
7 4 5 3 4 5 2 0 23 9 10 5 9 7 9 8
11 5 7 7 9 7 1 0 17 13 7 10 6 5 8 10

Выход:

103
................
..#.....###.#...
.......#...#.#..
....###..#.#.#..
.#..##.#...#....
...##.....#.....
..#####.#..#.#..
.#.#.###.#..##..
...#.......#....
..#....#..#...#.
.#.#.......#....
...##..#.#..##..
.#.#.........#..
......#..#.##...
.#..............
................

Я пробовал разные способы. Залить от максимального значения, затем от минимального значения, но это не работает для каждого ввода или требует усложнения кода. Есть идеи?

Мне интересен алгоритм со сложностью O (n ^ 2) или o (n ^ 3).

3

Решение

Резюме

Я хотел бы попытаться решить эту проблему с помощью непересекающаяся структура данных.

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

подробности

Для каждой высоты х (начиная с 0)

  1. Соедините все каменные плиты высотой x со своими соседями, если высота соседа <= x (сохранение связанных наборов флаговых камней в структуре данных непересекающихся наборов)

  2. Удалите все наборы, которые связаны с травой

  3. Отметьте все каменные плиты высотой x в оставшихся наборах как лужи

  4. Добавьте общее количество плит в оставшихся наборах к общему количеству

В конце т дает общий объем воды.

Работал Пример

0 0 0 0 0 1 0 0
0 1 1 1 0 1 0 0
0 1 0 2 1 2 4 5
0 1 1 2 0 2 4 5
0 3 3 3 3 3 3 4
0 3 0 1 2 0 3 4
0 3 3 3 3 3 3 0
0 0 0 0 0 0 0 0

Соедините все каменные плиты высотой 0 в наборы A, B, C, D, E, F

A A A A A 1 B B
A 1 1 1 A 1 B B
A 1 C 2 1 2 4 5
A 1 1 2 D 2 4 5
A 3 3 3 3 3 3 4
A 3 E 1 2 F 3 4
A 3 3 3 3 3 3 A
A A A A A A A A

Удалите каменные плиты, соединяющиеся с травой, и пометьте оставшиеся лужи

          1
1 1 1   1
1 C 2 1 2 4 5     #
1 1 2 D 2 4 5       #
3 3 3 3 3 3 4
3 E 1 2 F 3 4     #     #
3 3 3 3 3 3

Подсчитать оставшийся установленный размер t = 4

Подключите все по высоте 1

          G
C C C   G
C C 2 D 2 4 5     #
C C 2 D 2 4 5       #
3 3 3 3 3 3 4
3 E E 2 F 3 4     #     #
3 3 3 3 3 3

Удалите каменные плиты, соединяющиеся с травой, и пометьте оставшиеся лужи

      2   2 4 5     #
2   2 4 5       #
3 3 3 3 3 3 4
3 E E 2 F 3 4     # #   #
3 3 3 3 3 3

т = 4 + 3 = 7

Соедините все по высоте 2

      A   B 4 5     #
A   B 4 5       #
3 3 3 3 3 3 4
3 E E E E 3 4     # #   #
3 3 3 3 3 3

Удалите каменные плиты, соединяющиеся с травой, и пометьте оставшиеся лужи

            4 5     #
4 5       #
3 3 3 3 3 3 4
3 E E E E 3 4     # # # #
3 3 3 3 3 3

т = 7 + 4 = 11

Подключите все по высоте 3

            4 5     #
4 5       #
E E E E E E 4
E E E E E E 4     # # # #
E E E E E E

Удалите каменные плиты, соединяющиеся с травой, и пометьте оставшиеся лужи

            4 5     #
4 5       #
4
4     # # # #

После этого для высот 4 и 5 ничего не останется.

Шаг предварительной обработки для создания списков всех местоположений с каждой высотой должен означать, что алгоритм близок к O (n ^ 2).

2

Другие решения

Кажется, это работает хорошо. Идея состоит в том, что это рекурсивная функция, которая проверяет, существует ли «внешний поток», который позволит ему уйти на край. Если значения, которые не имеют такого выхода, будут лужами. Я проверил его на ваших двух входных файлах, и он работает довольно хорошо. Я скопировал вывод для этих двух файлов для вас. Прошу прощения за мое грязное использование глобальных переменных, а что нет, я решил, что именно концепция, стоящая за алгоритмом, имеет значение, а не хороший стиль 🙂

    #include <fstream>
#include <iostream>
#include <vector>
using namespace std;

int SIZE_X;
int SIZE_Y;bool **result;
int **INPUT;bool flowToEdge(int x, int y, int value, bool* visited) {
if(x < 0 || x == SIZE_X || y < 0 || y == SIZE_Y) return true;
if(visited[(x * SIZE_X) + y]) return false;
if(value < INPUT[x][y]) return false;

visited[(x * SIZE_X) + y] = true;

bool left = false;
bool right = false;
bool up = false;
bool down = false;left = flowToEdge(x-1, y, value, visited);
right = flowToEdge(x+1, y, value, visited);
up = flowToEdge(x, y+1, value, visited);
down = flowToEdge(x, y-1, value, visited);return (left || up || down || right);
}

int main() {

ifstream myReadFile;
myReadFile.open("test.txt");

myReadFile >> SIZE_X;
myReadFile >> SIZE_Y;

INPUT = new int*[SIZE_X];
result = new bool*[SIZE_X];
for(int i = 0; i < SIZE_X; i++) {
INPUT[i] = new int[SIZE_Y];
result[i] = new bool[SIZE_Y];
for(int j = 0; j < SIZE_Y; j++) {
int someInt;
myReadFile >> someInt;
INPUT[i][j] = someInt;
result[i][j] = false;
}
}for(int i = 0; i < SIZE_X; i++) {
for(int j = 0; j < SIZE_Y; j++) {
bool visited[SIZE_X][SIZE_Y];
for(int k = 0; k < SIZE_X; k++)//You can avoid this looping by using maps with pairs of coordinates instead
for(int l = 0; l < SIZE_Y; l++)
visited[k][l] = 0;

result[i][j] = flowToEdge(i,j, INPUT[i][j], &visited[0][0]);
}
}

for(int i = 0; i < SIZE_X; i++) {
cout << endl;
for(int j = 0; j < SIZE_Y; j++)
cout << result[i][j];
}
cout << endl;
}

Файл 16 на 16:

1111111111111111
1101111100010111
1111111011101011
1111000110101011
1011001011101111
1110011111011111
1100000101101011
1010100010110011
1110111111101111
1101101011011101
1010111111101111
1110011010110011
1010111111111011
1111110110100111
1011111111111111
1111111111111111

Файл 8 на 8

11111111
11111111
11011111
11110111
11111111
11000011
11111111
11111111

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

Работа включает в себя, каждый n должен будет проверить каждый узел. Тем не менее, с оптимизацией, мы должны быть в состоянии получить это намного ниже, чем n ^ 2 для большинства случаев, но это все еще алгоритм n ^ 3 в худшем случае … но создать это было бы очень сложно (при правильной логике оптимизации. .. динамическое программирование на победу!)

РЕДАКТИРОВАТЬ:

Измененный код работает при следующих обстоятельствах:

8 8
1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 1
1 0 1 1 1 1 0 1
1 0 1 0 0 1 0 1
1 0 1 1 0 1 0 1
1 0 1 1 0 1 0 1
1 0 0 0 0 1 0 1
1 1 1 1 1 1 1 1

И вот результаты:

11111111
10000001
10111101
10100101
10110101
10110101
10000101
11111111

Теперь, когда мы удаляем эту 1 внизу, мы не хотим видеть лужи.

8 8
1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 1
1 0 1 1 1 1 0 1
1 0 1 0 0 1 0 1
1 0 1 1 0 1 0 1
1 0 1 1 0 1 0 1
1 0 0 0 0 1 0 1
1 1 1 1 1 1 0 1

И это результаты

1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector