Разбор. Это, пожалуй, самая интересная задача, которую приходится здесь разбирать. Она отличается от остальных повышенной сложностью. Данное решение в корне отличается от авторского и не претендует быть лучшим. Однако оно имеет право на существование, так как решает данную задачу. Для решения этой задачи нам потребуется структура данных дек. Дек представляет собой очередь с одной стороны и стек с другой. Применяется крайне редко, но «метко». Пусть для определенности слева будет очередь, а справа – стек. Это значит, что снимать элементы дека теперь можно только спереди, а помещать как вперед, так и назад. Идея решения основана на обходе в ширину, но сильно модифицированном и оптимизированном, так как ограничения на время не позволяют писать его «в лоб». При реализации последнего метода нам придется как бы имитировать Васины действия, что будет работать очень долго. Представьте только, 100 * 100 обходов в ширину, и каждый из них для всех картинок размерностью от 1*1 до 100*100. Время работы колоссальное. Представим картинку в виде графа, вершинами которого являются пиксели (дальше - клетки). Каждый пиксель может быть связан с четырьмя другими по указанным правилам, это будут ребра. Заметим сразу, что в подобных задачах преобразовывать картинку в непосредственно граф не стоит! Можно пользоваться алгоритмом, оставаясь «в картинке», то есть переходить от одной вершины к другой по смежным ребрам (в данном случае, геометрическим частям клетки) пикселей. Возьмем на рассмотрение произвольную клетку (вершину), которую ещё не брали, и метку, изначально равную числу какому-нибудь а. Пусть это черная клетка (для определенности). Обыкновенным обходом в глубину пометим все черные клетки (вместе с исходной), до которых можно добраться по смежным клеткам, то есть, обнаружив очередную подходящую клетку, будем помещать в дек вперед и помечать числом а. Но, при просмотре соседних клеток, мы невольно будем натыкаться (если это будет в тесте) на белые клетки. Не игнорировать же их нам!.. Так будем помещать их в дек назад (если они конечно ещё непросмотренны), чтобы потом к ним вернуться, одновременно помечая их числом а+1. В этом состоит «изюминка» метода: мы одновременно используем два обхода – в ширину и в глубину посредством дека. И так действуем дальше: достали из дека клетку, обошли всех смежные с ней клетки, помечая их ее числом, а если «заглядываем» в клетки другого цвета, добавляем их в конец дека, и метим числом на 1 большим. Обойдя наконец все клетки(пиксели, вершины графа) картинки, мы получим матрицу с числами. Максимальное из них следует запомнить, так как это один из вариантов будущего ответа. Будем повторять это действие для каждой клетки картинки по очереди, начиная с а = 0. Минимальное из максимальных запомненных величин и есть ответ на задачу. Ведь действительно, каждое число характеризует количество переходов на другой цвет поля, что эквивалентно нажатию на начальный пиксель (тот, с которого начат очередной обход). Теперь опишем оптимизации, позволяющие ускорить программу. Заметим, что вовсе незачем прогонять алгоритм для каждой из клеток. Ведь если мы начинаем просмотр с какой-либо клетки и отмечаем сначала те клетки, до которых можно добраться из нее. Они будут с ней одного «номера» а. Так зачем нам в дальнейшем проверять эти клетки ещё раз, если они выполнят эту же работу? Пометим их так, чтобы было ясно, что с них начинать очередной обход не нужно. Это избавит программу от многочисленных повторных пробегов. Так же имеет смысл написать «заочное» решение для частных случаев. Код программы приведен ниже. #include <iostream> 1 #include <algorithm> using namespace std; int n, m, k; int mass[100][100]; int ans = 1000000; int met[100][100]; int mass1[100][100]; struct coord { int x; int y; coord() { x = 0; y = 0; } coord(int _x, int _y) { x = _x; y = _y; } }; void Out(int mass1[100][100]) { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) cout << mass1[i][j]; cout << endl; } cout << endl; } int BFS(int x, int y) { //массивы смещений относительно клетки int sx[4] = {-1, 0, 1, 0}; int sy[4] = {0, 1, 0, -1}; //структура данных - ДЕК coord dec[20011]; int front = 10006; //указатель на перед int back = 10005; //указатель на зад int size = 0; //размер дека //====================== int col = 0; //====================== mass1[x][y] = k; /**/ met[x][y] = 1; //====================== dec[front] = coord(x, y);// front++; //запихиваем в первую дек стартовую клетку size++; //============== while (size > 0) //пока есть непросмотренные клетки в деке { //достаем из дека клетку front--; coord u = dec[front]; size--; 2 //============== for (int i = 0; i < 4; ++i) { int x1 = u.x + sx[i]; int y1 = u.y + sy[i]; if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= m) { continue; } if (mass1[x1][y1] < k) //если мы ещё тут не были { if (mass[x1][y1] == mass[u.x][u.y])//если цвета клеток совпадают { mass1[x1][y1] = mass1[u.x][u.y]; dec[front] = coord(x1, y1); front++; size++; if (mass1[x1][y1] == k) // //помещаем в дек вперед // //метим клетку как помеченную met[x1][y1] = 1; } else { mass1[x1][y1] = mass1[u.x][u.y] + 1; dec[back] = coord(x1, y1);// back--; //помещаем в дек size++; // } if (mass1[x1][y1] > col) { col = mass1[x1][y1]; } } } } return col - k; } int main() { freopen("l.in", "r", stdin); freopen("l.out", "w", stdout); //======= Reading ==== cin >> n >> m; int col = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { char ch; cin >> ch; mass[i][j] = ch - '0'; 3 col+= mass[i][j]; met[i][j] = 0; mass1[i][j] = 0; } //== частные случаи ==== if (col == 0 || col == n * m) { cout << 0; return 0; } if (col > 0 && col < 4) { cout << 1; return 0; } if (col > n*m-4 && col < n*m) { cout << 1; return 0; } //=========================== k = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) if (met[i][j] == 0) { col = BFS(i, j); ans = min(ans, col); k = max(k + col + 1, col + 2); } cout << ans; return 0; } 4