Морской бой
Этот листок посвящен игре в Морской бой. Программы в этом листке
получают на вход поле для игры в Морской бой. Поле задается следующим
образом. Сначала указано количество строк в поле n
,
затем указано количество столбцов в поле m
.
Далее идет n
строк по m
символов в каждой строке. Каждый символ строки может быть либо точкой (.
),
либо диезом (#
). Точка означает, что данная
клетка пустая, диез означает, что данная клетка занята.
Пример задания поля:
4 6
###.#.
....#.
.#..#.
.#..#.
На этом поле три корабля - один вертикально размещенный 4-клеточный,
второй горизонтально размещенный трехклеточный, третий вертикально
размещенный двухклеточный.
Два корабля не могут соприкасаться по вертикали, горизонтали или
диагонали.
Размеры поля могут быть произвольными от 1 до 1000. Для хранения поля
удобно сделать глобальный массив int Map[1002][1002]. Элементы этого
массива будут равны 0, если клетка - пустая или 1 - если клетка занята.
Все остальные функции будут работать с этим массивов. Мы создадим
массив максимального размера, добавив еще 2 строки и два столбца для
хранения каемочки, ограничивающей наше поле. Эту каемочку нужно
заполнить нулями - для удобства использования во всех алгоритмах.
Кроме того, заведем две глобальные переменные n и m для хранения
размеров поля. Итак, начало каждой программы будет таким:
int n, m;
int Map[1002][1002];
Сами элементы поля будут храниться в элементах массива
Map[i][j]
, где
1≤i≤n
и 1≤j≤m
.
Программа обязательно должна содержать функцию ReadMap()
,
считывающую
данные и записывающую их в массив Map
и
функцию, решающую основную
задачу. При этом функция main()
должна иметь
вид вроде:
int main()
{
ReadMap();
cout<<CountShips()<<endl;
}
В разных задачах корабли могут быть различными. В задачах A-E корабли
являются отрезками прямых, лежащих на одной горизонтали или одной
вертикали, в задачах F-J - прямоугольниками, в задачах K-O -
произвольными связными фигурами.
Файловый ввод-вывод
Во всех задачах этого листка входные данные для программы записаны в файле input.txt
, а результат работы программы должен быть сохранен в файле output.txt
.
Поэтому нужно научиться работать с файлами. Файловый ввод-вывод ничем не отличается от консольного.
За единственным исключением – если данные читаются из файла,
то в любой момент можно вернуться к началу файла и считать все заново.
Для того, чтобы в C++ работать с файлами необходимо подключить заголовочный файл fstream
:
#include <fstream>
После этого можно объявлять объекты, привязанные к файлам: для чтения данных из файла используются
объекты типа ifstream
(аббревиатура от input file stream, для записи данных в файл
используются объекты типа ofstream
(output file stream). Например
ifstream fin; // Поток fin будем использовать для чтения данных
ofstream fout; // Поток fout будем использовать для вывода данных
Чтобы привязать тот или иной поток к файлу (открыть файл для чтения или для записи) используется
метод open
, которому необходимо передать параметр – текстовую строку, содержащую имя
открываемого файла.
fin.open("input.txt");
fout.open("output.txt");
После открытия файлов и привязки их к файловым потокам, работать с файлами можно
так же, как со стандартными потоками ввода-вывода cin
и cout
.
Например, чтобы вывести значение переменной x
в поток fout
используются
следующая операция
fout<<x;
А чтобы считать значение переменной из потока fin
fin>>x;
Для закрытия ранее открытого файла используется метод close()
без аргументов:
in.close();
out.close();
Закрытый файловый поток можно переоткрыть заново при помощи метода open
, привязав его
к тому же или другому файлу.
0: Разминка
В файле input.txt записаны два целых числа. Выведите в файл output.txt их сумму.A: Количество кораблей
Определите количество кораблей на поле.Пример
Ввод |
Вывод |
4 6 ###.#. ....#. .#..#. .#..#. |
3
|
Подсказка. Нужно считать количество верхних (левых) концов кораблей. Как определить, является ли клетка верхним (левым) концом?
B: Самый большой корабль
Определите количество клеток в самом большом корабле.Пример
Ввод |
Вывод |
4 6 ###.#. ....#. .#..#. .#..#.
|
4
|
Подсказка. Найдя верхний (левый) конец корабля нужно посчитать, сколько в нем клеток.С: Корректность карты
Дана карта. Проверьте, является ли размещение кораблей на ней корректным. Выведите YES или NO.Пример
Ввод |
Вывод |
4 6 ###.#. ....#. .#..#. .#..#.
|
YES
|
4 6 .##... .#.... .#.... ...... | NO |
4 6 ..##.. .#.... .#.... ...... | NO |
Подсказка. Карта является корректной, если каждая
занятая кораблем клетка не имеет диагональных соседних занятых клеток,
а также не имеет одновременно соседей по горизонтали или по вертикали.D: Меткий выстрел
Дана
карта и дана клетка на поле. Клетка задана в виде двух чисел - номера
строка i и номера столбца j. Строки нумеруются сверху вниз от 1,
столбцы нумеруются слева направо от 1.
Игрок выстрелил в эту клетку,
после чего потопил весь тот корабль, в который попал выстрел (а если не
попал, то ничего не потопил). Выведите получившуюся карту.
При выводе поля не нужно выводить его размеры, только изображение самого поля.
Пример
Ввод |
Вывод |
4 6 ###.#. ....#. .#..#. .#..#. 3 2
|
###.#. ....#. ....#. ....#.
|
Е: Свободное место
Задана карта. Определите максимальный размер корабля, который можно установить на эту карту не нарушая правила игры.
Пример
Ввод |
Вывод |
4 6 ###.#. ....#. #..... #.....
|
4
|
Подсказка. Сначала попробуйте найти место для
вертикального корабля, затем - для горизонтального. Для поиска места
находим свободную клетку, в которую можно разместить корабль, затем
начинаем достаивать корабль от этой клетки пока это возможно. Если
стало невозможно - обрываем корабль и идем дальше по строке, затем
переходим к следующей строке и т.д.F: Количество кораблей-2
Теперь
все корабли могут быть произвольными прямоугольниками, опять-таки не
соприкасающимися. Определите количество кораблей на поле.Пример
Ввод |
Вывод |
4 6 ###..# ...... .###.# .###.. |
4
|
Подсказка. Нужно опять считать количество верхних левых углов кораблей.
G: Самый большой корабль-2
Определите количество клеток в самом большом корабле.Пример
Ввод |
Вывод |
4 6 ###..# ...... .###.# .###..
|
6
|
Подсказка. Найдя верхний левый угол корабля нужно посчитать, сколько в нем клеток, определив его высоту и ширину.H: Меткий выстрел-2
Дана
карта и дана клетка на поле. Клетка задана в виде двух чисел - номера
строка i и номера столбца j. Строки нумеруются сверху вниз от 1,
столбцы нумеруются слева направо от 1.
Игрок выстрелил в эту клетку,
после чего потопил весь тот корабль, в который попал выстрел (а если не
попал, то ничего не потопил). Выведите получившуюся карту.
Пример
Ввод |
Вывод |
4 6 ###.#. ....#. ##..#. ##..#. 3 2
|
4 6 ###.#. ....#. ....#. ....#.
|
I: Корректность карты-2
Дана карта. Проверьте, является ли размещение кораблей на ней корректным. Выведите YES или NO.Пример
Ввод |
Вывод |
4 6 ###..# ...... ##..#. ##..#.
|
YES
|
4 6 .###.. .#.#.. .###.. ...... | NO |
4 6 ..##.. .#.... .#.... ...... | NO |
Подсказка. Нужно обнаруживать и выделять все корабли.
Обнаружив корабль, можно проверить, что он прямоугольный и не касается
других кораблей. При этом сам корабль можно сразу же стирать с поля.J: Свободное место-2
Задана карта. Определите максимальный размер корабля (в клетках), который можно установить на эту карту не нарушая правила игры.
В этой задаче ограничения на n и m будут уменьшены.
Пример
Ввод |
Вывод |
4 6 ###.#. ...... #..... #.....
|
8
|
Подсказка. Переберем все возможные размещения нового корабля.
K: Меткий выстрел-3
Теперь все корабли могут быть
произвольными связными множествами клеток (связность определяется по общим сторонам
клеток), опять-таки не соприкасающимися. Также возможна ситуация, когда
один корабль целиком находится внутри другого корабля, но при этом они
не соприкасаются ни сторонами, ни углами.
Дана
карта и дана клетка на поле. Игрок выстрелил в эту клетку,
после чего потопил весь тот корабль, в который попал выстрел (а если не
попал, то ничего не потопил). Выведите получившуюся карту.
Пример
Ввод |
Вывод |
6 6 .##### #....# #.##.# #.#..# #....# ###### 3 3
|
.##### #....# #....# #....# #....# ######
|
Подсказка. Нужно научиться выделять каждый отдельный корабль при помощи волнового алгоритма.
L: Количество кораблей-3
Дана карта. Определите количество кораблей на этой карте.
Пример
Ввод |
Вывод |
6 6 .##### #....# #.##.# #.#..# #....# ###### |
2
|
Подсказка. Будем по очереди находить и стирать корабли, считая их число.
M: Самый большой корабль-3
Определите количество клеток в самом большом корабле.Пример
Ввод |
Вывод |
6 6 .##### #....# #.##.# #.#..# #....# ######
|
19
|
Подсказка. Модифицируем волновой алгоритм так, чтобы он возвращал количество клеток в обнаруженном корабле.N: Корректность карты-3
Дана карта. Проверьте, является ли размещение кораблей на ней корректным. Выведите YES или NO.Пример
Ввод |
Вывод |
6 6 .##### #....# #.##.# #.#..# #....# ######
|
YES
|
6 6 .##### ##...# #.##.# #.#..# #....# ###### | NO |
Подсказка. Нужно модифицировать волновой алгоритм так,
чтобы он красил каждый корабль в свой цвет. После этого проверить,
соприкасаются ли покрашенные корабли или нет.O: Свободное место-3
Дана карта. Определите максимальный размер корабля (в клетках), который можно установить на эту карту не нарушая правила игры.
Пример
Ввод |
Вывод |
4 6 ###.#. ....#. #..... #.....
|
5
|
Подсказка. Допустим, мы нашли свободную клетку.
Запустим волновой алгоритм для строительства нового корабля из этой
клетки. Проделаем эту операцию со всеми клетками.