|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
Найти количество островков из единиц
Доброе времени суток! Я новичок в программировании. Мне не понятен вот этот код. Написан он очень уж умно. А мне нужен примитивный, просто код, что бы его можно было легко читать. А этот код даже "загуглив" практически каждую строчку, требует практики, что бы его понять. Может быт, кто- нибудь смог бы его переписать более просто? на базовом уровне?
Код:
#include <cmath> #include <fstream> #include <iostream> #include <set> #include <string> #include <utility> ///////////////////////////////////////////////////////////////////////////////////////// typedef std::string T_str; typedef std::pair < int, int > T_cell; typedef std::set < T_cell > T_cells; ///////////////////////////////////////////////////////////////////////////////////////// void go_to_cell_with_cells_and_visited_cells ( T_cell cell, T_cells const & cells, T_cells & visited_cells ) { visited_cells.insert( cell ); for ( auto adj_cell_it = cells.begin (); adj_cell_it != cells.end (); ++adj_cell_it ) { if ( visited_cells.count( *adj_cell_it ) == 0 && ( abs( cell.first - adj_cell_it->first ) + abs( cell.second - adj_cell_it->second ) == 1 ) ) { go_to_cell_with_cells_and_visited_cells ( *adj_cell_it, cells, visited_cells ); } }//for } ///////////////////////////////////////////////////////////////////////////////////////// int get_islands_count_of( T_cells const & cells ) { int res_count = 0; T_cells visited_cells; for ( auto cell_it = cells.begin (); cell_it != cells.end (); ++cell_it ) { if ( visited_cells.count( *cell_it ) == 0 ) { ++res_count; go_to_cell_with_cells_and_visited_cells ( *cell_it, cells, visited_cells ); } }//for return res_count; } ///////////////////////////////////////////////////////////////////////////////////////// int main() { std::locale::global(std::locale("")); const T_str INPUT_FILENAME = "input.txt"; const T_str OUTPUT_FILENAME = "output.txt"; std::ifstream ifile( INPUT_FILENAME ); T_cells cells; if( !ifile ) { std::cout << "Невозможно прочитать данные из файла." << std::endl; } else { int matr_dim = 0; ifile >> matr_dim; for( int i = 0; i < matr_dim; ++i ) { for( int j = 0; j < matr_dim; ++j ) { int cell_val = 0; ifile >> cell_val; if( cell_val ) { cells.insert ( T_cell( i, j ) ); } }//for }//for std::ofstream ofile( OUTPUT_FILENAME ); ofile << get_islands_count_of( cells ); }//else system("pause"); } этот код к такому заданию, только я не понял, в этом алгоритме есть обход в глубину или нету? Задача Острова Каждый элемент квадратной матрицы размеренности N x N равен нулю, либо единице. Найдите количество «островов», образованных единицами. Под «островом» понимается группа единиц (либо одна единица), со всех сторон окруженная нулями (или краями матрицы). Единицы относятся к одному «острову», если из одной из них можно перейти к другой «наступая» на единицы, расположенные в соседних клетках. Соседними являются клетки, граничащие по горизонтали или вертикали. Уточним, что одна единица тоже считается островом. Также предлагаю считывать матрицу из файла. Входные данные В первой строке файла INPUT.TXT записано натуральное число N не больше 100 - размер квадратной матрицы. В следующих N строках задаются элементы матрицы через пробел. Выходные данные В файл OUTPUT.TXT выведите единственное число - количество островов. Пример INPUT.TXT 4 OUTPUT.TXT 5 1 0 1 1 1 0 0 0 0 0 1 1 1 0 1 0 1 0 0 1 0 0 0 1 1 Решение задачи Итак, это классическая задача на поиск в глубину графа. Понятно, что надо обходить матрицу и каким-то образом вычислять количество островов. Вариант решения такой: после того, как мы попадаем на остров, надо это зафиксировать увеличив переменную-результат на единицу. Чтобы второй раз не посчитать один и тот же остров, сразу после посещения необходимо его уничтожить, т.е. присвоить всем клеткам острова значение ноль. Поскольку тест задачи не слишком мал, стоит написать процедуру уничтожения островов, назовем ее"count". Чтобы во время выполнения процедуру не "выскочить" за пределы массива, сделаем его не размером N x N, а размеров N+2 x N+2, это даст нам возможность окружить искомый массив размеромN x N нулями. Последний раз редактировалось lmikle, 29.07.2015 в 19:32. |
#2
|
|||
|
|||
Ну, я бы тогда по твоему алгоритму сделал бы что-то типа:
Код:
var A : Array Of Integer; // Карта // "Удаление" острова procedure DeleteIsland(AI, AJ : Integer); var I, J : Integer; begin A[I,J] := 0; For I := AI-1 To AI+1 Do For J := AJ-1 To AJ+1 Do If (I >= Low(A)) And (I <= High(A)) And (J >= Low(A[i])) And (J <= High(A[i])) Then If A[I,J] = 1 Then DeleteIsland(I,J); end; // Подсчет островов function CountIslands : Integer; var I, J : Integer; begin Result := 0; For I := Low(A) To High(A) Do For J := Low(A[i]) To High(A[i]) Do If A[I,J] = 1 Then Begin Inc(Result); DeleteIsland(I,J); End; end; Кратко: CountIslands - пробегает по всем ячейкам матрицы и если находит 1, то увеличивает счетчик и вызывает процедуру удаления острова. DeleteIsland - удаляет элемент острова в текущей ячейке, а потом рекурсивно вызывает себя для удалени всех соседних ячеек (если они равны 1). If с большим условием - что бы не вылететь за границу массива. |
#3
|
|||
|
|||
Ой, не посмотрел, что надо на C/C++.
С другой стороны, алгоритм действия понятен. Дальше сам должен смочь перевести. |
#4
|
|||
|
|||
что бы переделать, нужно знать паскаль. За попытку спасибо. Может быть еще будет и на с ++
|
#5
|
|||
|
|||
Да что тут знать? Там циклы и обращение к массиву. Больше ничего нету. Мне просто лень переводить на C, бо как сама задача решена.
Вот приведенный выше код, переписанная на С (ну, загрузку в массив сам напишешь, там просто...): Код:
// Array and size, should be updated during input data loading int A[][]; // Array int n = 0; // Size of an array void DeleteIsland(int ai, aj) { A[i][j] = 0; for (int i = ai-1; i <= ai+1; ++i) for (int j = aj-1; j < aj+1; ++j) if (i >=0 && i < n && j >= 0 && j < n) if (A[i],[j] == 1) DeleteIsland(i,j); } int CountIslands() { int Result = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) if (A[i][j] == 1) { Result++; DeleteIsland(i,j); } return Result; } Последний раз редактировалось lmikle, 30.07.2015 в 00:12. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Luster (30.07.2015)
|
#6
|
||||
|
||||
То же самое, только на си, чуть правильней (диагонали не должны учитываться по заданию) и с немного меньшим числом проверок во время выполнения, хотя выглядит корявее:
Код:
void deleteIsland(char **map, int x, y) { if (map[y][x] == 0) return; map[y][x] = 0; if (y > 0) deleteIsland(map, x, y-1); if (y < n-1) deleteIsland(map, x, y+1); if (x > 0) deleteIsland(map, x-1, y); if (x < n-1) deleteIsland(map, x+1, y); } int islandsCount(char **map, int N) { int result = 0; for (int y = 0; y < N; ++y) for (int x = 0; x < N; ++x) if (map[y][x] != 0) { ++result; deleteIsland(map, x, y); } return result; } jmp $ ; Happy End! The Cake Is A Lie. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Luster (30.07.2015)
|
#7
|
|||
|
|||
Bargest, да, про диагонали ты прав. Что-то поленился я
Вообще, надо подумать как можно такой паттерн проверки написать красиво... Двумя циклами?.. Код:
int i; for (i=x-1; i<x+2; ++i) deleteIsland(map,i,y); for (i=y-1; i<y+2; ++i) deleteIsland(map,x,i); Да и 2 лишнии итерации, которые совсем ни к селу. ни к городу... ЗЫ. if'ы специально сейчас пропустил... Последний раз редактировалось lmikle, 30.07.2015 в 00:20. |