Решение кроссворда R2-D2

Создано: 21 ноября 2024 г.

Отвечено с использованием OpenAI 01 Preview от OpenAI01

Вопрос

Решить на c++
Условия
R2-D2 решает кроссворд, составленный специально для дроидов. В этом кроссворде в клеточки нужно писать не буквы, а цифры.

Кроссворд представляет из себя клетчатое поле
n
×
m
n×m. Некоторые клетки заблокированы, а все остальные — свободные. Словом в кроссворде назовем максимальный по включению вертикальный или горизонтальный отрезок свободных клеток. Иными словами, слово — это отрезок клеток одного столбца или строки, ограниченный с обоих сторон краем поля или заблокированными клетками.

Исходно, каждая свободная клетка кроссворда содержит какую-то цифру. Цель дроида — поменять цифры таким образом, чтобы каждое слово в кроссворде являлось палиндромом. Палиндром — это строка, читающаяся одинаково как слева-направо так и справа-налево. При этом, чем меньше суммарное изменение цифр в кроссворде по сравнению с исходными, тем лучше. Поэтому, требуется найти такое решение кроссворда, при котором сумма по всем свободным клеткам модулей разности исходной цифры и цифры в решении, была минимальна.

Помогите R2-D2 решить кроссворд так, чтобы суммарное изменение цифр было минимально. Несложно заметить, что всегда есть способ заполнить кроссворд так, чтобы все слова были палиндромами. Например, заполнить все свободные клетки одинаковыми цифрами. Поэтому, решение всегда существует.



Входные данные

В первой строке дано два целых числа
n
n и
m
m — размеры поля (
1

n
,
m

1

000
1≤n,m≤1000).

В следующих
n
n строках дано по
m
m символов — описание кроссворда. Символы могут быть равны « . » или цифрам. Символ « . » соответствует заблокированной клетке. А символ с цифрой
d
d соответствует свободной клетке, в которой исходно написана цифра
d
d.



Выходные данные

Выведите описание искомого решения кроссворда в том же формате, что и во входных данных. Если решений несколько, можете вывести любое.



Система оценки

Баллы за каждую подзадачу начисляются только в случае, если все тесты для этой подзадачи и необходимых подзадач успешно пройдены.


Подзадача Баллы Ограничения Необходимые подзадачи Информация о проверке
1 7
n
,
m

4
n,m≤4 первая ошибка
2 6
n
=
1
n=1 первая ошибка
3 34
n
,
m

100
n,m≤100 1 первая ошибка
4 27
n
,
m

300
n,m≤300 1, 3 первая ошибка
5 26 Без дополнительных ограничений 1, 2, 3, 4 первая ошибка




Примечание

В первом примере в кроссворде есть
6
6 слов, соответствующих каждому столбцу и строке поля. В оптимальном решении, суммарное изменение цифр равно
20
20.

Во втором примере, помимо слов длины
1
1, есть следующие слова: 2020 , 05 , 10 . В оптимальном решении, суммарное изменение цифр равно
7
7.

Примеры данных
Входные данные
1
3 3
123
456
789
2
4 3
.2.
.05
.2.
10.
3
10 10
.538......
...4...4..
...459157.
5...6..6..
7.16304815
9...6..1..
5...8..2..
138631.351
2...3...7.
7.......4.
Выходные данные
1
323
454
323
2
.1.
.22
.2.
11.
3
.535......
...4...3..
...531135.
5...3..1..
2.11800811
1...6..1..
5...8..3..
136631.343
2...3...7.
5.......4.

Мысль

Определяю суть задачи

Даю сигнал динамической программой для поиска максимального количества разрешенных ячеек. Это напоминает мне о бронировании сидений.

Минимизируя затраты, идем к цели.

Определяю подход

Ищем числа для каждой позиции, чтобы получился палиндром, и минимизируем общую стоимость.

Присваиваю новые цифры

Я распределяю новые цифры по симметричным позициям, чтобы минимизировать сумму абсолютных разностей с исходными цифрами.

Определяю минимальную стоимость

Я подбираю цифры для каждой пары чисел, минимизируя общую стоимость. Вычисляю затраты для каждой цифры от 0 до 9 и выбираю минимальную.

Визуализируя изменения

Теперь я рассматриваю изменения в каждой паре позиций, вычисляя стоимость каждой цифры и выбирая минимальную. Для слов нечетной длины, центр занимает собственную цифру.

Оцениваю сложность

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

Реализующая стратегия

Итак, я собираюсь отслеживать позиции и цифры для каждого слова в строках и столбцах, обновляя сетку new_digits, чтобы избежать конфликта новых и исходных цифр.

Рассматриваю конфликт

Присваивая цифры ячейкам, участвующим в обеих словах, нужно обеспечить их согласованность, чтобы избежать противоречий.

Ищем альтернативы

Я думаю над другим способом: собираю все ограничения для каждой позиции и представляю их как граф. Узлы это слова, а грани соединяют симметричные позиции.

Разбираю задачу

Рассматриваю разбиение позиций на компоненты и назначение цифр, минимизируя затраты для каждого компонента. Testing cost function для выбора лучших комбинаций.

Создание и оптимизация

Я строю граф, используя Union-Find, чтобы объединить зеркальные позиции слов и минимизируя стоимость, присваивая цифры.

Анализируя алгоритм

Анализирую временную сложность алгоритма, учитывая обработку пар для каждого слова и вычисление затрат для каждого компонента. Временная сложность составляет O(n*m * 10).

Распределяю позиции

Я разрабатываю метод объединения позиций на сетке, создавая уникальные идентификаторы и вычисляя стоимость для каждой компоненты, чтобы оптимизировать их.

Расстановка акцентов

Реализую это как можно эффективнее. Важно помнить: уникальные идентификаторы, инициализация для свободных ячеек и обновление сетки.

Оцениваю выполнимость

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

Ответ

To solve this problem efficiently, we can leverage the fact that any positions that are symmetric in a word must contain the same digit in the final solution. Furthermore, if a cell is part of multiple words, it needs to have the same digit across all those words. This observation leads us to model the problem as grouping cells into connected components where each component must be assigned the same digit.

Here's how we can approach the problem:

  1. Represent Cells Uniquely: Map each free cell (i, j) to a unique identifier, such as id = i * m + j, where m is the number of columns.

  2. Initialize Disjoint Set Union (DSU): Use DSU (also known as Union-Find) to keep track of connected components. Each free cell starts as its own parent.

  3. Connect Symmetric Positions:

    • For Each Word (both horizontal and vertical):
      • Identify pairs of symmetric positions.
      • Use DSU to union these pairs, ensuring they belong to the same component.
  4. Gather Components:

    • After all unions, iterate over all cells to find their root parent.
    • Group cells by their root parent to form components.
  5. Assign Digits to Components:

    • For each component, consider all possible digits from 0 to 9.
    • Calculate the total cost of changing all cells in the component to each digit.
    • Choose the digit with the minimal total cost.
    • Assign this digit to all cells in the component.
  6. Reconstruct the Grid:

    • Replace the digits in the free cells with the newly assigned digits.
    • Leave the blocked cells (represented by '.') unchanged.
  7. Output the Result:

    • Print the grid in the same format as the input.

Here's the C++ code implementing the above approach:

#include <iostream> #include <vector> #include <string> #include <algorithm> #include <unordered_map> #include <cstring> using namespace std; const int MAX_N = 1000; int n, m; char grid[MAX_N][MAX_N + 1]; int parent[MAX_N * MAX_N]; vector<int> positions[MAX_N * MAX_N]; int find(int x) { if (parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } void unite(int x, int y) { int px = find(x), py = find(y); if (px != py) parent[py] = px; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // Read input cin >> n >> m; for (int i = 0; i < n; ++i) { cin >> grid[i]; } // Initialize DSU for free cells for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { int id = i * m + j; if (grid[i][j] != '.') { parent[id] = id; } else { parent[id] = -1; // Blocked cell } } } // Process horizontal words for (int i = 0; i < n; ++i) { vector<int> word; for (int j = 0; j <= m; ++j) { if (j < m && grid[i][j] != '.') { word.push_back(i * m + j); } else { int len = word.size(); for (int k = 0; k < len / 2; ++k) { unite(word[k], word[len - 1 - k]); } word.clear(); } } } // Process vertical words for (int j = 0; j < m; ++j) { vector<int> word; for (int i = 0; i <= n; ++i) { if (i < n && grid[i][j] != '.') { word.push_back(i * m + j); } else { int len = word.size(); for (int k = 0; k < len / 2; ++k) { unite(word[k], word[len - 1 - k]); } word.clear(); } } } // Collect components unordered_map<int, vector<int>> components; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { int id = i * m + j; if (grid[i][j] != '.') { int root = find(id); components[root].push_back(id); } } } // Assign digits to components for (auto& comp : components) { int best_d = 0, min_cost = INT_MAX; int cost[10] = {0}; for (int id : comp.second) { int i = id / m, j = id % m; int orig_d = grid[i][j] - '0'; for (int d = 0; d <= 9; ++d) { cost[d] += abs(d - orig_d); } } for (int d = 0; d <= 9; ++d) { if (cost[d] < min_cost) { min_cost = cost[d]; best_d = d; } } // Assign best digit to all positions in the component for (int id : comp.second) { int i = id / m, j = id % m; grid[i][j] = best_d + '0'; } } // Output the result for (int i = 0; i < n; ++i) { cout << grid[i] << '\n'; } return 0; }

Explanation:

  • Reading the Input: The grid is read into a 2D character array, with each cell either being a digit or '.' for blocked cells.

  • Initializing DSU: Only free cells (digits) are initialized in the DSU. Blocked cells are marked differently to avoid processing them.

  • Processing Words:

    • Horizontal Words: We iterate through each row, collecting continuous sequences of free cells. For each word, we union symmetric positions.
    • Vertical Words: Similarly, we iterate through each column.
  • Building Components: After all unions, we group cells by their root parent to form components.

  • Assigning Digits:

    • For each component, we calculate the cost of changing all its cells to each possible digit.
    • We choose the digit with the minimal total cost and assign it to all cells in the component.
  • Output: Finally, we print the modified grid, ensuring that all words are palindromes with minimal total changes.

Поделиться этим Q&A