Проблема определяется следующим образом:
Вам дали квадрат. Площадь выложена плоскими плитками размером 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).
Я хотел бы попытаться решить эту проблему с помощью непересекающаяся структура данных.
Алгоритм будет состоять в том, чтобы выполнять итерацию по всем высотам на карте, выполняя операцию заливки на каждой высоте.
Для каждой высоты х (начиная с 0)
Соедините все каменные плиты высотой x со своими соседями, если высота соседа <= x (сохранение связанных наборов флаговых камней в структуре данных непересекающихся наборов)
Удалите все наборы, которые связаны с травой
Отметьте все каменные плиты высотой x в оставшихся наборах как лужи
Добавьте общее количество плит в оставшихся наборах к общему количеству
В конце т дает общий объем воды.
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).
Кажется, это работает хорошо. Идея состоит в том, что это рекурсивная функция, которая проверяет, существует ли «внешний поток», который позволит ему уйти на край. Если значения, которые не имеют такого выхода, будут лужами. Я проверил его на ваших двух входных файлах, и он работает довольно хорошо. Я скопировал вывод для этих двух файлов для вас. Прошу прощения за мое грязное использование глобальных переменных, а что нет, я решил, что именно концепция, стоящая за алгоритмом, имеет значение, а не хороший стиль 🙂
#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