Закрасить значения в матрице так, чтобы закрашенная была единственная в строке и столбце

Дана матрица 9 на 9, заполненная нулями и единицами. Нужно написать алгоритм закрашивания единиц таким образом, чтобы эта закрашенная единица была единственной в строке и столбце(как на рисунке). введите сюда описание изображения

Предположения:

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

Может быть есть решение лучше?


Ответы (1 шт):

Автор решения: JohnSUN

Решение для таких задач обычно не сложно. Оно трудоёмкое для компьютера (очень много попыток нужно сделать пока доберёшься до результата), но в коде всё довольно просто:

Option Explicit

' Эти переменные будут использоваться внутри рекурсивной части - поэтому объявлены здесь:
Dim aRange As Range     ' Исходный диапазон
Dim nSize As Integer    ' Размер доски (по умолчанию 9)
Dim aData As Variant    ' Значения ячеек (1 или "не 1") на доске
' Два одномерных массива - размеры будут переопределены после получения размера доски nSize
Dim bFree() As Boolean  ' для быстрой проверки есть ли уже ладья в этой строке
Dim aRes() As Integer   ' для координат ладей по строкам

Sub place_N_Towers()
Dim sStartCell As String ' Верхняя левая ячейка квадратного диапазона
Dim isGoog As Boolean    ' Результат расстановки ладей оказался успешным?
Dim i As Integer

    sStartCell = InputBox("Адрес верхней левой ячейки доски", "Положение данных на текущем листе", "B2")
    nSize = InputBox("Количество расставляемых ладей", "Размер доски", 9)
    If nSize < 2 Then Exit Sub
    On Error Resume Next
    Set aRange = Range(sStartCell).Resize(nSize, nSize)
    On Error GoTo 0
    If aRange Is Nothing Then Exit Sub
    aData = aRange.Value
    ReDim bFree(1 To nSize)
    ReDim aRes(1 To nSize)
    For i = 1 To nSize
        bFree(i) = True
    Next i
    Call TryNext(1, isGoog)
    If isGoog Then  ' Успешно - закрасить нужные ячейки
        For i = 1 To nSize
            aRange.Cells(aRes(i), i).Interior.Color = rgbOrangeRed
        Next i
    Else    ' Не получилось - огорчить пользователя:
        Call MsgBox("Для такого набора единиц решение не может быть найдено", vbCritical, "Не в этот раз")
    End If
End Sub

Sub TryNext(ByVal nColumn As Integer, ByRef isGoog As Boolean)
' Эта процедура практически такая же как у Вирта
' Только добавлена проверка "в этой ячейке единица?"
Dim nRow As Integer
    nRow = 0
    Do
        nRow = nRow + 1
        If aData(nRow, nColumn) = 1 Then
            isGoog = False
            If bFree(nRow) Then
                aRes(nColumn) = nRow
                bFree(nRow) = False
                If nColumn < nSize Then
                    Call TryNext(nColumn + 1, isGoog)
                    If Not isGoog Then
                        bFree(nRow) = True
                    End If
                Else
                    isGoog = True
                End If
            End If
        End If
    Loop Until isGoog Or nRow = nSize
End Sub
→ Ссылка