Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.81/21: Рейтинг темы: голосов - 21, средняя оценка - 4.81
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23

Олимпиадная задача на bfs

11.08.2020, 01:04. Показов 4485. Ответов 46
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Была задана вот такая задача:

Всем известна увлекательная игра «Морской бой». Сейчас играть в морской бой можно не только с соседом по парте, но и с компьютером. Игра c компьютером ведется на прямоугольном поле произвольных размеров N×M, где N - количество строк, M - количество столбцов. Приближается чемпионат Мира по морскому бою. Планируется вести его трансляцию в режиме реального времени: демонстрировать карту с кораблями и выводить статистику: количество целых, подбитых и уничтоженных кораблей, находящихся на поле. Требуется написать программу для подсчета статистики.

Корабль на поле — это связанная фигура, стоящая из одной или нескольких рядом лежащих клеток, имеющих общую сторону. Корабли могут быть абсолютно любых форм и размеров!

Входные данные
Первая строка входного файла INPUT.TXT содержит два целых числа N и M (1≤ N,M ≤ 103), разделённых пробелами - размеры игрового поля. Далее идут N строк по M символов - описание игрового поля.

Английская буква 'X' обозначает подбитую клетку корабля, 'S' - не подбитую клетку корабля, '-' – свободное водное пространство.
Выходные данные
В выходной файл OUTPUT.TXT выведите через пробел три числа:

количество целых кораблей
количество подбитых кораблей
количество уничтоженных кораблей
Пример №1
C++
1
2
3
4
5
6
7
INPUT.TXT
3 8
---SSS--
XX--S-X-
X-S---S-
OUTPUT.TXT
2 1 1
Начал решать, тесты из примера все прошли. Но в дальнейших проверках встречается превышение выделенной памяти из-за чего программа не засчитывается. Кто может подсказать, как ускорить программу? Также не откажусь от куска алгоритма, который поможет это решить (готовое решение также приветствуется, буду разбираться). Вот мой код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
using namespace std;
   
int arr[1001][1001];
int n, m, k = 0;
 
vector<vector<int> > types;
 
bool check(vector<int> vc){
    for(int i : vc) if(i != vc[0]) return false;
    return true;
}
void G(int i, int j){
    if(0 <= i && i < n && 0 <= j && j < m){
        if(arr[i][j]){
            types[k].push_back(arr[i][j]);
            arr[i][j] = 0;
            G(i + 1, j);
            G(i - 1, j);
            G(i, j + 1);
            G(i, j - 1);
        }
    }
}
int main() {
   char x;
   cin >> n >> m;
   types.resize(n * m);
   for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            cin >> x;
            if(x == '-') arr[i][j] = 0;
            else if(x == 'S') arr[i][j] = 1;
            else if(x == 'X') arr[i][j] = 2;
        }
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) {
                G(i, j);
                k++;
            }
        }
    int ans[] = {0, 0, 0};
    for(int i = 0; i < k; i++){
       if(check(types[i])){
           if(types[i][0] == 1) ans[0]++;
           else ans[2]++;
       } else ans[1]++;
    }
    for(int i : ans) cout << i << " ";
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
11.08.2020, 01:04
Ответы с готовыми решениями:

Олимпиадная задача по программированию. PascalABC.NET. Задача L. Переключение между окнами
Когда пользователь работает в операционной системе Winux, у него часто запущено несколько приложений. Каждое из приложений работает в...

Считалка. Олимпиадная задача по программированию
Ирочка попросила маму придумать новую считалочку. Мама тут же ей &quot;выдала&quot;. Пусть в кругу N человек. Это число N будем изменять...

Олимпиадная задача
Кот Василий узнал, что у соседа Димы, проживающего от него через какое-то количество заборов завелись мыши. Так как в своём хозяйстве всех...

46
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 11:16
Цитата Сообщение от programmist- Посмотреть сообщение
Начал решать, тесты из примера все прошли. Но в дальнейших проверках встречается превышение выделенной памяти из-за чего программа не засчитывается. Кто может подсказать, как ускорить программу?
Для начала - надо передавать массив по ссылке, а не по значению - bool check(const vector<int> &vc)

Добавлено через 2 минуты
Цитата Сообщение от programmist- Посмотреть сообщение
types[k].push_back(arr[i][j]);
Сделай в начале функции G(....)
C++
1
types[k].reserve(m)
Добавлено через 2 минуты
Цитата Сообщение от programmist- Посмотреть сообщение
int arr[1001][1001];
И сделай вместо этого динамический массив m х n
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 13:54  [ТС]
Исправил как вы написали, но теперь нехватка памяти происходит на еще более раннем тесте
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 13:58
Цитата Сообщение от programmist- Посмотреть сообщение
Исправил как вы написали, но теперь нехватка памяти происходит на еще более раннем тесте
Покажи, как сделал
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 13:59  [ТС]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
using namespace std;
   
int** arr = new int* [1001];
int n, m, k = 0;
 
vector<vector<int> > types;
 
bool check(const vector<int> &vc){
    for(int i : vc) if(i != vc[0]) return false;
    return true;
}
void G(int i, int j){
    types[k].reserve(m);
    if(0 <= i && i < n && 0 <= j && j < m){
        if(arr[i][j]){
            types[k].push_back(arr[i][j]);
            arr[i][j] = 0;
            G(i + 1, j);
            G(i - 1, j);
            G(i, j + 1);
            G(i, j - 1);
        }
    }
}
int main() {
   char x;
   cin >> n >> m;
   for(int i = 0; i < n; i++) arr[i] = new int[m];
   types.resize(n * m);
   for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            cin >> x;
            if(x == '-') arr[i][j] = 0;
            else if(x == 'S') arr[i][j] = 1;
            else if(x == 'X') arr[i][j] = 2;
        }
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) {
                G(i, j);
                k++;
            }
        }
    int ans[] = {0, 0, 0};
    for(int i = 0; i < k; i++){
       if(check(types[i])){
           if(types[i][0] == 1) ans[0]++;
           else ans[2]++;
       } else ans[1]++;
    }
    for(int i : ans) cout << i << " ";
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 14:07
Цитата Сообщение от programmist- Посмотреть сообщение
int** arr = new int* [1001];
C++
1
int** arr = nullptr;
Добавлено через 45 секунд
C++
1
2
3
4
5
int main() {
   char x;
   cin >> n >> m;
arr = new int *[n];
   for(int i = 0; i < n; i++) arr[i] = new int[m];
Добавлено через 42 секунды
И удаление в конце не забудь сделать

Добавлено через 4 минуты
Цитата Сообщение от programmist- Посмотреть сообщение
types.resize(n * m);
А здесь точно нужно n * m элементов?
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 14:19  [ТС]
Насчет types тут и правда хватит только n * m / 2 + 1, тк максимальный вариант расположения - в шахматном порядке через 1

Добавлено через 4 минуты
И снова превышение выделенной памяти \(0_0)/
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 14:26
Цитата Сообщение от programmist- Посмотреть сообщение
types[k].reserve(m);
Попробуй это убрать

Добавлено через 5 минут
Кстати, а зачем types[k] сделан массивом, vector<vector<int> >? Туда, в types[k], больше одного элемента добавляется?
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 14:28  [ТС]
Дошли на 1 тест дальше, чем были, но далее опять тоже самое

Добавлено через 1 минуту
Да, туда добавляются варианты "клеток" корабля, на примере из теста types будет иметь вид:
1 1 1 1
2 2 2
1 2
1
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 14:31
Цитата Сообщение от programmist- Посмотреть сообщение
Дошли на 1 тест дальше, чем были, но далее опять тоже самое
Покажи новый код
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 14:35  [ТС]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <vector>
using namespace std;
    
int** arr = nullptr;
int n, m, k = 0;
  
vector<vector<int> > types;
  
bool check(const vector<int> &vc){
    for(int i : vc) if(i != vc[0]) return false;
    return true;
}
void G(int i, int j){
    if(0 <= i && i < n && 0 <= j && j < m){
        if(arr[i][j]){
            types[k].push_back(arr[i][j]);
            arr[i][j] = 0;
            G(i + 1, j);
            G(i - 1, j);
            G(i, j + 1);
            G(i, j - 1);
        }
    }
}
int main() {
   char x;
   cin >> n >> m;
   arr = new int *[n];
   for(int i = 0; i < n; i++) arr[i] = new int[m];
   types.resize(n * m / 2 + 1);
   for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            cin >> x;
            if(x == '-') arr[i][j] = 0;
            else if(x == 'S') arr[i][j] = 1;
            else if(x == 'X') arr[i][j] = 2;
        }
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) {
                G(i, j);
                k++;
            }
        }
    int ans[] = {0, 0, 0};
    for(int i = 0; i < k; i++){
       if(check(types[i])){
           if(types[i][0] == 1) ans[0]++;
           else ans[2]++;
       } else ans[1]++;
    }
    for(int i : ans) cout << i << " ";
    for(int i = 0; i < n; i++) delete[]arr[i];
    delete[]arr;
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 14:41
Попробуй еще убрать переменную k
C++
1
2
3
   for(int i = 0; i < n; i++) arr[i] = new int[m];
   //types.resize(n * m / 2 + 1);
   for(int i = 0; i < n; i++)
Добавлено через 37 секунд
C++
1
2
3
4
5
6
7
8
9
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) 
{
types.push_back({});
                G(i, j);
//                k++;
            }
        }
Добавлено через 34 секунды
C++
1
2
3
4
5
void G(int i, int j){
    if(0 <= i && i < n && 0 <= j && j < m){
        if(arr[i][j]){
            types.back().push_back(arr[i][j]);
            arr[i][j] = 0;
Добавлено через 3 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
int ans[] = {0, 0, 0};
for(auto &type: types)
{
    if(!check(type))
        ans[1]++;
    else if(type[0] == 1) 
        ans[0]++;
    else 
        ans[2]++;
 
}
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 14:43  [ТС]
Исправил, k убрал, вот новый код, но дальше по тестам так и не сдвинулись

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <vector>
using namespace std;
    
int** arr = nullptr;
int n, m;
  
vector<vector<int> > types;
  
bool check(const vector<int> &vc){
    for(int i : vc) if(i != vc[0]) return false;
    return true;
}
void G(int i, int j){
    if(0 <= i && i < n && 0 <= j && j < m){
        if(arr[i][j]){
            types.back().push_back(arr[i][j]);
            arr[i][j] = 0;
            G(i + 1, j);
            G(i - 1, j);
            G(i, j + 1);
            G(i, j - 1);
        }
    }
}
int main() {
   char x;
   cin >> n >> m;
   arr = new int *[n];
   for(int i = 0; i < n; i++) arr[i] = new int[m];
   //types.resize(n * m / 2 + 1);
   for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            cin >> x;
            if(x == '-') arr[i][j] = 0;
            else if(x == 'S') arr[i][j] = 1;
            else if(x == 'X') arr[i][j] = 2;
        }
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) {
                types.push_back({});
                G(i, j);
            }
        }
    int ans[] = {0, 0, 0};
    for(auto &i : types){
       if(check(i)){
           if(i[0] == 1) ans[0]++;
           else ans[2]++;
       } else ans[1]++;
    }
    for(int i : ans) cout << i << " ";
    for(int i = 0; i < n; i++) delete[]arr[i];
    delete[]arr;
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 14:48
Цитата Сообщение от programmist- Посмотреть сообщение
Исправил, k убрал, вот новый код, но дальше по тестам так и не сдвинулись
Давай ещё вот так сделаем
C++
1
2
3
4
5
6
7
8
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++){
            if(arr[i][j]) {
                types.push_back({});
                G(i, j);
types.back().shrink_to_fit();
            }
        }
Добавлено через 1 минуту
Там точно по памяти отваливается?
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 14:56  [ТС]
Точно, тест занимает 48мб при пороге в 32мб, при чем время меньше 0,1с TL тут и не светит

Добавлено через 3 минуты
Изменения не помогли, все также. Думаю, дело уже в алгоритме, рекурсия, возможно, много съедает, буду пробовать без нее
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 15:02
А массив arr здесь вообще нужен? Vj;tn pfgjkyznm chfpe
Цитата Сообщение от programmist- Посмотреть сообщение
Точно, тест занимает 48мб при пороге в 32мб, при чем время меньше 0,1с TL тут и не светит
Для начала, попробуй ещё заменить int в своих массивах на char. Здесь достаточно 8-ми бит

Добавлено через 1 минуту
И что-то подозреваю, что массив types здесь не нужен. Для решения достаточно только массива arr

Добавлено через 3 минуты
Тебе нужно найти корабль и вычислить его тип, одновременно заменяя все его клетки, например, на пробел, потом найти следующий корабль и т.д.
0
653 / 466 / 183
Регистрация: 23.04.2019
Сообщений: 1,987
11.08.2020, 15:04
Цитата Сообщение от programmist- Посмотреть сообщение
тест занимает 48мб
я особо в код не вчитывался, но можно заменить тип arr с int на какой нибудь uint8_t?
так-же с вектором
ещё переполнение памяти может быть из-за рекурсии, может лучше её заменить на циклы?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 15:05
Цитата Сообщение от AndryS1 Посмотреть сообщение
ещё переполнение памяти может быть из-за рекурсии, может лучше её заменить на циклы?
Нет, здесь проблема не в рекурсии
0
0 / 0 / 0
Регистрация: 11.08.2020
Сообщений: 23
11.08.2020, 15:05  [ТС]
Так, char не помог, стало занимать вообще 52мб. Насчет types в принципе я согласен, в данном случае просто было легче и понятнее решить через доп вектор, но по итогу тогда имеем превышение памяти
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
11.08.2020, 15:11
Цитата Сообщение от programmist- Посмотреть сообщение
Так, char не помог, стало занимать вообще 52мб. Насчет types в принципе я согласен, в данном случае просто было легче и понятнее решить через доп вектор, но по итогу тогда имеем превышение памяти
Не, не лучше. Это ж олимпиадная задача, в ней надо думать. Попробуй сделать без него

Добавлено через 27 секунд
C++
1
2
3
4
5
6
7
8
9
10
char *arr;
int main() 
{
    char x;
    cin >> n >> m;
    arr = new char[m * n];
    
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            cin >> arr[i * n + j];
Добавлено через 1 минуту
Не надо преобразовывать символы поля в числа, так и сравнивай с 'X' 'S' '-'
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.08.2020, 15:11
Помогаю со студенческими работами здесь

Олимпиадная задача
program zad4; Var n,i,k:longint; c:char; Procedure closing; begin close(input); close(output); halt(0); end; ...

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

Олимпиадная задача
Провайдеры, предоставляющие услуги доступа в интернет широкому пользователю, часто составляют различную статистику посещений сайтов из...

Олимпиадная задача
Маленький мальчик, плывя с родителями вверх по речке, отпустил кораблик. После этого они прошли еще вверх 15 мин и сделали 30 мин....

олимпиадная задача
1)Отгадать целое число которое загадал компьютер в определённом диапазоне? 2)Lesson:В первом полугодии 2007-08 учебного года занятия...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru