Классный алгоритм проверки поля судоку?

Кто-нибудь знает простой алгоритм проверки правильности Судоку-Конфигурации? Самый простой алгоритм, который я придумал, - это (для платы размера n) в псевдокоде.

for each row
  for each number k in 1..n
    if k is not in the row (using another for-loop)
      return not-a-solution

..do the same for each column

Но я совершенно уверен, что должно быть лучшее (в смысле более элегантное) решение. Эффективность совсем не важна.

Добавьте сюда все алгоритмы: проверьте, нет ли чисел больше, чем ваше количество квадратов на стороне.

StriplingWarrior 13.10.2009 22:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
1
67 892
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

Подумайте только: разве вам не нужно также проверять числа в каждом квадрате 3x3?

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

Я не знаю, правда ли это: первая строка 1..9, вторая строка 2..9,1, третья 3..9,1,2 ... приведет к правильным строкам и столбцам, но не к квадратам 3x3 . Или я что-то здесь упускаю?

Ralph M. Rickenbach 14.11.2008 12:25

@malach: Вы абсолютно правы. Без ограничения box это латинский квадрат. Таким образом, набор действительных завершенных судоку определенного размера является подмножеством всех латинских квадратов этого размера. Например, сетка 4x4 со строками [1234] [2143] [3412] [4321] является латинским квадратом, но не правильным судоку 2x2.

Michael Madsen 14.11.2008 13:08

Вам нужно отметить все три (строки, столбцы и поля).

Bill the Lizard 15.11.2008 06:01
Ответ принят как подходящий

Вам необходимо проверить все ограничения судоку:

  • проверить сумму в каждой строке
  • проверьте сумму в каждом столбце
  • проверьте сумму на каждой коробке
  • проверьте наличие повторяющихся номеров в каждой строке
  • проверьте наличие повторяющихся номеров в каждом столбце
  • проверьте наличие повторяющихся номеров на каждом поле

это всего 6 проверок ... с использованием подхода грубой силы.

Можно использовать своего рода математическую оптимизацию, если вы знаете размер доски (например, 3x3 или 9x9).

Редактировать: объяснение ограничения суммы: сначала проверка суммы (и остановка, если сумма не равна 45) намного быстрее (и проще), чем проверка дубликатов. Это простой способ отказаться от неправильного решения.

Судоку не требует сумм.

cjm 14.11.2008 22:12

Сумма любой строки или столбца будет одинаковой, т.е. 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45, а проверки на дублирование связаны с тем, что 45 можно получить другими способами, если есть дубликаты. Приведенные выше правила ЯВЛЯЮТСЯ ограничениями, необходимыми для получения действительной конфигурации.

Tristan Warner-Smith 24.02.2009 01:18

Этот ответ является неверен. Ограничения суммы не нужны, потому что нет способа получить сумму 45 каким-либо другим способом без нарушения одного из 3 фактических ограничений.

sykora 29.04.2009 13:21

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

Svante 29.04.2009 13:25

Сначала проверка суммы (и остановка, если сумма не равна 45) намного быстрее, чем проверка дубликатов. Могут ли люди, которые пропустили математические занятия, перестать голосовать против этого, пожалуйста?

Radu094 14.05.2009 17:19

Я согласен с тем, что этот алгоритм будет быстрее для большинства реальных проверок, но в вопросе конкретно говорится, что эффективность «совершенно не важна», и он ищет «элегантности». Этот ответ, хотя он всегда дает правильные ответы, безусловно, не является самым эффективным или самым элегантным решением, опубликованным здесь. Мне странно, что именно он был выбран в качестве ответа. Однако я не думаю, что он заслуживает отрицательных голосов.

StriplingWarrior 13.10.2009 22:47

Radu094: почему бы тебе не отредактировать свой ответ, объяснив причину появления сумм? Я знаю причину, но добавление этого в ответ также позволит избежать некоторых отрицательных голосов (ИМО).

Dom De Felice 23.05.2010 14:26

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

Kannan Goundan 04.04.2011 21:29

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

Mohammad Ali 15.06.2016 07:30

@KannanGoundan Скорее всего, у переменной с левым сдвигом сложность выше, чем у суммы?

Paamand 23.09.2017 23:46

@Paamand: Да, левый сдвиг и побитовая проверка требует вдвое больше операций ALU, чем проверка суммы. (Но мне интересно, действительно ли современные суперскалярные процессоры будут выполнять левый сдвиг параллельно с побитовой или следующей итерацией ...)

Kannan Goundan 25.09.2017 04:00

возможно, в судоку есть только одно правило: sudopedia.enjoysudoku.com/Rule.html

Ray Tayek 20.01.2019 08:31

@ Radu094, в то время как я могу видеть вашу точку зрения на сумму в редактировании (и это круто), но вы сказали прямо вверху «ограничения судоку» - это не совсем так. Хорошо, если столбец или строка не повторяются, суммируется до 45, но это не явное ограничение для игры Судоку. Поэтому я бы выделил это как «подразумеваемое» ограничение, а не правила игры.

mavili 17.07.2019 19:08

Было бы очень интересно проверить, если:

when the sum of each row/column/box equals n*(n+1)/2
and the product equals n!
with n = number of rows or columns

этого достаточно для правил судоку. Потому что это позволило бы использовать алгоритм O (n ^ 2), суммирующий и умножающий правильные ячейки.

Глядя на n = 9, сумма должна быть 45, произведений 362880.

Вы бы сделали что-то вроде:

for i = 0 to n-1 do
  boxsum[i] := 0;
  colsum[i] := 0;
  rowsum[i] := 0;
  boxprod[i] := 1;
  colprod[i] := 1;
  rowprod[i] := 1;    
end;

for i = 0 to n-1 do
  for j = 0 to n-1 do
    box := (i div n^1/2) + (j div n^1/2)*n^1/2;
    boxsum[box] := boxsum[box] + cell[i,j];
    boxprod[box] := boxprod[box] * cell[i,j];
    colsum[i] := colsum[i] + cell[i,j];
    colprod[i] := colprod[i] * cell[i,j];
    rowsum[j] := colsum[j] + cell[i,j];
    rowprod[j] := colprod[j] * cell[i,j];
   end;
end;

for i = 0 to n-1 do
  if boxsum[i] <> 45
  or colsum[i] <> 45
  or rowsum[i] <> 45
  or boxprod[i] <> 362880
  or colprod[i] <> 362880
  or rowprod[i] <> 362880
   return false;

Это было бы отличным решением ... к сожалению, простые множители можно переставить, чтобы обмануть его ... например, последовательность: 4 4 4 9 5 7 9 2 1 имеет сумму 45 и произведение 9!

Marco M. 14.11.2008 13:25

marco, ха, я написал тестовую программу, чтобы проверить это, и собирался торжественно опубликовать контрпример, но вы меня победили. Я должен прочитать комментарии, прежде чем приступить к делу!

SPWorley 29.04.2009 16:35

Допустим, int судоку [0..8,0..8] - это поле судоку.

bool CheckSudoku(int[,] sudoku)
{
    int flag = 0;

// Check rows
for(int row = 0; row < 9; row++)
{
    flag = 0;
    for (int col = 0; col < 9; col++)
    {
        // edited : check range step (see comments)
        if ((sudoku[row, col] < 1)||(sudoku[row, col] > 9)) 
        {
            return false;
        }

        // if n-th bit is set.. but you can use a bool array for readability
        if ((flag & (1 << sudoku[row, col])) != 0) 
        {
            return false;
        }

        // set the n-th bit
        flag |= (1 << sudoku[row, col]); 
    }
}

// Check columns
for(int col= 0; col < 9; col++)
{
    flag = 0;
    for (int row = 0; row < 9; row++)
    {
        if ((flag & (1 << sudoku[row, col])) != 0)
        {
            return false;
        }
        flag |= (1 << sudoku[row, col]);
    }
}

// Check 3x3 boxes
for(int box= 0; box < 9; box++)
{
    flag = 0;
    for (int ofs = 0; ofs < 9; ofs++)
    {
        int col = (box % 3) * 3;
        int row = ((int)(box / 3)) * 3;

        if ((flag & (1 << sudoku[row, col])) != 0)
        {
            return false;
        }
        flag |= (1 << sudoku[row, col]);
    }
}
return true;

}

Если кто-то введет недопустимое значение (например, 0 или 10), этот алгоритм все равно будет оцениваться как истинный. Просто придирчивый :-) Можно исправить еще одним тестом в конце каждого внутреннего цикла: flag xor 0x1FF = 0

Ralph M. Rickenbach 14.11.2008 13:19

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

Marco M. 14.11.2008 13:26

Вы не можете сказать, что O (3 (n ^ 2)) лучше или хуже, чем O (n ^ 2), не принимая во внимание реализацию отдельных операций и архитектуру, на которой они работают; это тот же класс сложности. Вы должны проверить данные 3 * n ^ 2. Если вы делаете одну большую петлю или три меньших, то это то же самое.

Marco M. 19.11.2008 15:03

У Питера Норвига есть отличная статья о решении головоломок судоку (с питоном),

https://norvig.com/sudoku.html

Может быть, это слишком много для того, чем вы хотите заниматься, но в любом случае это отличное чтение

решение и проверка - это разные вещи, не так ли?

ckarbass 17.09.2011 02:40

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

Tomerikoo 21.10.2020 10:52

Всем, кто сталкивается с этим сообщением: обратите внимание, что вопрос требует рекомендации.

fcdt 21.10.2020 11:39

Создайте наборы ячеек, каждый из которых содержит 9 ячеек, и создайте наборы для вертикальных столбцов, горизонтальных строк и квадратов 3x3.

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

Так я писал это раньше.

jmucchiello 29.04.2009 16:49

Предположим, что ваша доска идет от 1 до n.

Создадим проверочный массив, заполним его и проверим.

grid [0-(n-1)][0-(n-1)]; //this is the input grid
//each verification takes n^2 bits, so three verifications gives us 3n^2
boolean VArray (3*n*n) //make sure this is initialized to false


for i = 0 to n
 for j = 0 to n
  /*
   each coordinate consists of three parts
   row/col/box start pos, index offset, val offset 
  */

  //to validate rows
  VArray( (0)     + (j*n)                             + (grid[i][j]-1) ) = 1
  //to validate cols
  VArray( (n*n)   + (i*n)                             + (grid[i][j]-1) ) = 1
  //to validate boxes
  VArray( (2*n*n) + (3*(floor (i/3)*n)+ floor(j/3)*n) + (grid[i][j]-1) ) = 1
 next    
next

if every array value is true then the solution is correct. 

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

Вы можете извлечь все значения в наборе (строка, столбец, поле) в список, отсортировать его, а затем сравнить с '(1, 2, 3, 4, 5, 6, 7, 8, 9)

array = [1,2,3,4,5,6,7,8,9]  
sudoku = int [][]
puzzle = 9 #9x9
columns = map []
units = map [] # box    
unit_l = 3 # box width/height
check_puzzle()    


def strike_numbers(line, line_num, columns, units, unit_l):
    count = 0
    for n in line:
        # check which unit we're in
        unit = ceil(n / unit_l) + ceil(line_num / unit_l) # this line is wrong - rushed
        if units[unit].contains(n): #is n in unit already?
             return columns, units, 1
        units[unit].add(n)
        if columns[count].contains(n): #is n in column already?
            return columns, units, 1
        columns[count].add(n)
        line.remove(n) #remove num from temp row
    return columns, units, line.length # was a number not eliminated?

def check_puzzle(columns, sudoku, puzzle, array, units):
    for (i=0;i< puzzle;i++):
        columns, units, left_over = strike_numbers(sudoku[i], i, columns, units) # iterate through rows
        if (left_over > 0): return false

Без тщательной проверки это должно работать (с небольшой отладкой), только зациклившись дважды. O (n ^ 2) вместо O (3 (n ^ 2))

если не ошибаюсь O (n ^ 2) == O (3 (n ^ 2))?

Kami 22.04.2011 02:00

@Kami Вы не ошиблись. Я даже не помню, чтобы писал этот ответ. Если бы у меня снова было время, я бы применил совершенно другой подход. Забавно, как многому можно научиться за 2 с небольшим года: P

Josh Smeaton 22.04.2011 06:34

Я сделал это однажды для классного проекта. Я использовал в общей сложности 27 наборов для представления каждой строки, столбца и поля. Я проверял числа по мере того, как добавлял их в каждый набор (каждое размещение числа приводит к добавлению числа к 3 наборам, строке, столбцу и коробке), чтобы убедиться, что пользователь ввел только цифры 1- 9. Единственный способ заполнить набор - это правильно заполнить его уникальными цифрами. Если все 27 наборов были заполнены, загадка решалась. Настройка сопоставлений пользовательского интерфейса с 27 наборами была немного утомительной, но остальную логику было несложно реализовать.

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

char VerifySudoku(char grid[81])
{
    for (char r = 0; r < 9; ++r)
    {
        unsigned int bigFlags = 0;

        for (char c = 0; c < 9; ++c)
        {
            unsigned short buffer = r/3*3+c/3;

                        // check horizontally
            bitFlags |= 1 << (27-grid[(r<<3)+r+c]) 
                        // check vertically
                     |  1 << (18-grid[(c<<3)+c+r])
                        // check subgrids
                     |  1 << (9-grid[(buffer<<3)+buffer+r%3*3+c%3]);

        }

        if (bitFlags != 0x7ffffff)
            return 0; // invalid
    }

    return 1; // valid
}

Вот статья профессора математики Дж. Ф. Крука: Карандашно-бумажный алгоритм решения головоломок судоку

Эта статья была опубликована в апреле 2009 года и получила широкую огласку как однозначное решение судоку (проверьте в Google "Судоку Дж. Ф. Крука") .

Помимо алгоритма, существует еще и математическое доказательство того, что алгоритм работает (профессор признал, что судоку ему не очень интересен, поэтому он бросил математику в бумагу, чтобы сделать ее более увлекательной).

Проверьте каждую строку, столбец и коробку, чтобы они содержали числа от 1 до 9, без дубликатов. Большинство ответов здесь уже обсуждают это.

Но как это сделать эффективно? Ответ: Используйте петлю вроде

result=0;
for each entry:
  result |= 1<<(value-1)
return (result==511);

Каждое число устанавливает один бит результата. Если все 9 чисел уникальны, самые младшие 9 биты будут установлены. Таким образом, тест «проверка дубликатов» - это просто проверка того, что все 9 бит установлены, что совпадает с результатом тестирования == 511. Вам необходимо выполнить 27 таких проверок ... по одной для каждой строки, столбца и поля.

Я бы написал интерфейс с функциями, которые получают поле судоку и возвращают истину / ложь, если это решение. Затем реализуйте ограничения как отдельные классы проверки для каждого ограничения.

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

Довольно общий шаблон. ;-)

Вы, конечно, можете улучшить это, чтобы указать, какое поле предположительно неверно, и так далее.

Первое ограничение, просто проверьте, все ли поля заполнены. (Простой цикл) Вторая проверка, все ли числа находятся в каждом блоке (вложенные циклы) Третья проверка полных строк и столбцов (почти такая же процедура, как указано выше, но другая схема доступа)

если сумма и умножение строки / столбца равно правому числу 45/362880

Как Марко М. упоминает в другом комментарии: «Простые множители можно переставить, чтобы обмануть его ... например, последовательность: 4 4 4 9 5 7 9 2 1 имеет сумму 45 и произведение 9!»

Ryan 07.11.2012 02:28

Создайте массив логических значений для каждой строки, столбца и квадрата. Индекс массива представляет собой ценить, помещенный в эту строку, столбец или квадрат. Другими словами, если вы добавите 5 во вторую строку, первый столбец, вы установите для строк [2] [5] значение true, а также столбцов [1] [5] и квадратов [4] [5], чтобы указать что строка, столбец и квадрат теперь имеют значение 5.

Независимо от того, как представлена ​​ваша исходная доска, это может быть простой и очень быстрый способ проверить ее на полноту и правильность. Просто возьмите числа в том порядке, в котором они появляются на доске, и начните строить эту структуру данных. Когда вы размещаете числа на доске, это становится операцией O (1), чтобы определить, дублируются ли какие-либо значения в данной строке, столбце или квадрате. (Вы также захотите проверить, что каждое значение является допустимым числом: если они дадут вам пустое или слишком большое число, вы знаете, что доска не заполнена.) Когда вы дойдете до конца доски, вы я буду знать, что все значения верны, и больше никаких проверок не требуется.

Кто-то также заметил, что для этого можно использовать любую форму Set. Массивы, расположенные таким образом, представляют собой лишь особенно легкую и производительную форму Set, которая хорошо работает для небольшого, последовательного фиксированного набора чисел. Если вы знаете размер своей платы, вы также можете выбрать побитовое маскирование, но это, вероятно, слишком утомительно, учитывая, что эффективность для вас не так уж и важна.

Немного неясно, как вы заполняете квадраты (строки и столбцы кажутся достаточно очевидными). Вы рассматриваете это как матрицу 9x9, в которой каждый квадрат 3x3 выложен в одну строку? Это не может быть правдой, не так ли?

ForeverLearning 20.08.2014 20:47

@JoranBeasley: Вы понимаете, как StriplingWarrior представляет себе квадраты?

ForeverLearning 20.08.2014 20:48

@Dilip: В судоку каждый квадрат 3x3 может иметь значение только один раз. Итак, если вы назначите индекс каждому из этих квадратов 3x3, вы можете проверить, есть ли в данном квадрате номер, найдя массив по этому индексу, а затем найдя логическое значение, соответствующее проверяемому числу. Неважно, как вы рассчитываете индекс каждого квадрата 3x3 - сверху вниз, влево-вправо, как угодно - пока вы последовательны.

StriplingWarrior 20.08.2014 22:57

Вероятно, это не подходит для Op, но я пришел сюда в поисках ответа.

Tyler 20.10.2017 02:11

@ Тайлер: Я рад, что это было вам полезно. Просто из любопытства, можете ли вы объяснить, почему это может не подходить для OP?

StriplingWarrior 20.10.2017 18:06

@StriplingWarrior Похоже, ему нужен самый простой и легкий для чтения алгоритм, который, на мой взгляд, будет повторять каждую группу (строку, столбец, прямоугольник). Я пытался найти более эффективный алгоритм, поскольку был скорее упражнением в компьютерной науке, чем реальной реализацией. На самом деле это довольно удобно для чтения, что является дополнительным бонусом.

Tyler 23.10.2017 18:19

Это мое решение на Python, я рад видеть, что оно самое короткое :)

Код:

def check(sud):
    zippedsud = zip(*sud)

    boxedsud=[]
    for li,line in enumerate(sud):
        for box in range(3):
            if not li % 3: boxedsud.append([])    # build a new box every 3 lines
            boxedsud[box + li/3*3].extend(line[box*3:box*3+3])

    for li in range(9):
        if [x for x in [set(sud[li]), set(zippedsud[li]), set(boxedsud[li])] if x != set(range(1,10))]:
            return False
    return True  

И исполнение:

sudoku=[
[7, 5, 1,  8, 4, 3,  9, 2, 6],
[8, 9, 3,  6, 2, 5,  1, 7, 4], 
[6, 4, 2,  1, 7, 9,  5, 8, 3],
[4, 2, 5,  3, 1, 6,  7, 9, 8],
[1, 7, 6,  9, 8, 2,  3, 4, 5],
[9, 3, 8,  7, 5, 4,  6, 1, 2],
[3, 6, 4,  2, 9, 7,  8, 5, 1],
[2, 8, 9,  5, 3, 1,  4, 6, 7],
[5, 1, 7,  4, 6, 8,  2, 3, 9]]

print check(sudoku)        

Если у вас есть какие-либо улучшения или вопросы, не стесняйтесь комментировать!

Kami 04.04.2011 16:00

Для python 3 используйте list(zip(**))

Rowland Mtetezi 15.10.2020 18:33

Вот мой в C. Пройдите каждую клетку только один раз.

int checkSudoku(int board[]) {
  int i;
  int check[13] = { 0 };

  for (i = 0; i < 81; i++) {
    if (i % 9 == 0) {
      check[9] = 0;
      if (i % 27 == 0) {
        check[10] = 0;
        check[11] = 0;
        check[12] = 0;
      }
    }

    if (check[i % 9] & (1 << board[i])) {
      return 0;
    }
    check[i % 9] |= (1 << board[i]);

    if (check[9] & (1 << board[i])) {
      return 0;
    }
    check[9] |= (1 << board[i]);

    if (i % 9 < 3) {
      if (check[10] & (1 << board[i])) {
        return 0;
      }
      check[10] |= (1 << board[i]);
    } else if (i % 9 < 6) {
      if (check[11] & (1 << board[i])) {
        return 0;
      }
      check[11] |= (1 << board[i]);
    } else {
      if (check[12] & (1 << board[i])) {
        return 0;
      }
      check[12] |= (1 << board[i]);
    }
  }
}

Во-первых, вам нужно сделать логическое «правильное». Затем создайте цикл for, как было сказано ранее. Код для цикла и всего после него (в java) такой, как указано, где field - это 2D-массив с равными сторонами, col - другой с такими же размерами, а l - 1D:

for(int i=0; i<field.length(); i++){
    for(int j=0; j<field[i].length; j++){
        if (field[i][j]>9||field[i][j]<1){
            checking=false;
            break;
        }
        else{
            col[field[i].length()-j][i]=field[i][j];
        }
    }
}

Я не знаю точного алгоритма проверки полей 3x3, но вы должны проверить все строки в поле и столбце с помощью «/*array name goes here*/[i].contains(1)&&/*array name goes here*/[i].contains(2)» (продолжайте, пока не достигнете длины строки) внутри другого цикла для.

Вот что я только что сделал для этого:

boolean checkers=true;
String checking = "";
    if (a.length/3==1){}
    else{
       for(int l=1; l<a.length/3; l++){
            for(int n=0;n<3*l;n++){
                for(int lm=1; lm<a[n].length/3; lm++){
                    for(int m=0;m<3*l;m++){
                    System.out.print("    "+a[n][m]);
                    if (a[n][m]<=0){
                    System.out.print("        (Values must be positive!)        ");
                    }
                    if (n==0){
                        if (m!=0){
                        checking+ = ", "+a[n][m];
                    }
                    else{
                        checking+=a[n][m];
                    }
                }
                else{
                    checking+ = ", "+a[n][m];
                }
            }
                    }
            System.out.print("        "+checking);
            System.out.println();
                }
       }
            for (int i=1;i<=a.length*a[1].length;i++){
        if (checking.contains(Integer.toString(i))){

        }
        else{
            checkers=false;
        }
            }
        }
    checkers=checkCol(a);
    if (checking.contains("-")&&!checking.contains("--")){
        checkers=false;
    }
    System.out.println();
    if (checkers==true){
        System.out.println("This is correct! YAY!");
    }
    else{
        System.out.println("Sorry, it's not right. :-(");
    }
}
private static boolean checkCol(int[][]a){
    boolean checkers=true;
    int[][]col=new int[][]{{0,0,0},{0,0,0},{0,0,0}};
    for(int i=0; i<a.length; i++){
        for(int j=0; j<a[i].length; j++){
            if (a[i][j]>9||a[i][j]<1){
                checkers=false;
                break;
            }
            else{
                col[a[i].length-j][i]=a[i][j];
            }
        }
    }
    String alia = "";
    for(int i=0; i<col.length; i++){
        for(int j=1; j<=col[i].length; j++){
            alia=a[i].toString();
            if (alia.contains(""+j)){
                alia=col[i].toString();
                if (alia.contains(""+j)){}
                else{
                    checkers=false;
                }   
            }
            else{
                checkers=false;
            }
        }
    }
    return checkers;
}

Был один баг, но я его забыл. :-(

user2425429 28.05.2013 18:17

Вот хороший читабельный подход в Python:

from itertools import chain                                                                                            

def valid(puzzle):                                                                                                     
    def get_block(x,y):                                                                                                
        return chain(*[puzzle[i][3*x:3*x+3] for i in range(3*y, 3*y+3)])                                               
    rows = [set(row) for row in puzzle]                                                                                
    columns = [set(column) for column in zip(*puzzle)]                                                                 
    blocks = [set(get_block(x,y)) for x in range(0,3) for y in range(0,3)]                                             
    return all(map(lambda s: s == set([1,2,3,4,5,6,7,8,9]), rows + columns + blocks))         

Каждый квадрат 3x3 называется блоком, а их 9 в сетке 3x3. Предполагается, что головоломка вводится как список списков, каждый внутренний список которого представляет собой строку.

Вы можете проверить, решена ли судоку, двумя аналогичными способами:

  • Убедитесь, что номер уникален в каждой строке, столбце и блоке.

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

Но есть способ получше.

  • Судоку решается, если каждая строка, столбец и блок содержат перестановку чисел (от 1 до 9).

Это требует только проверки каждой строки, столбца и блока, вместо того, чтобы делать это для каждого числа. Простая реализация состояла бы в том, чтобы иметь битовое поле с числами от 1 до 9 и удалять их при итерации столбцов, строк и блоков. Если вы попытаетесь удалить недостающий номер или поле не будет пустым, судоку решена неправильно.

def solution(board):
    for i in board:
        if sum(i) != 45:
            return "Incorrect"

    for i in range(9):
        temp2 = []
        for x in range(9):
            temp2.append(board[i][x])

        if sum(temp2) != 45:
            return "Incorrect"

    return "Correct"

board = []
for i in range(9):
    inp = raw_input()
    temp = [int(i) for i in inp]
    board.append(temp)

print solution(board)

Это должен быть temp2.append(board[x][i]), иначе он может быть неправильным, я думаю, или?

Rowland Mtetezi 15.10.2020 18:51

Вот очень краткая версия на Swift, которая использует только массив Ints для отслеживания групп из 9 чисел и выполняет итерацию судоку только один раз.

import UIKit

func check(_ sudoku:[[Int]]) -> Bool {

    var groups = Array(repeating: 0, count: 27)

    for x in 0...8 {
        for y in 0...8 {
            groups[x] += 1 << sudoku[x][y] // Column (group 0 - 8)
            groups[y + 9] += 1 << sudoku[x][y] // Row (group 9 - 17)
            groups[(x + y * 9) / 9 + 18] += 1 << sudoku[x][y] // Box (group 18 - 27)
        }
    }

    return groups.filter{ $0 != 1022 }.count == 0
}

let sudoku = [
    [7, 5, 1,  8, 4, 3,  9, 2, 6],
    [8, 9, 3,  6, 2, 5,  1, 7, 4],
    [6, 4, 2,  1, 7, 9,  5, 8, 3],
    [4, 2, 5,  3, 1, 6,  7, 9, 8],
    [1, 7, 6,  9, 8, 2,  3, 4, 5],
    [9, 3, 8,  7, 5, 4,  6, 1, 2],
    [3, 6, 4,  2, 9, 7,  8, 5, 1],
    [2, 8, 9,  5, 3, 1,  4, 6, 7],
    [5, 1, 7,  4, 6, 8,  2, 3, 9]
]

if check(sudoku) {
    print("Pass")
} else {
    print("Fail")
}

Одна небольшая оптимизация, которую вы можете сделать, заключается в том, что вы можете проверять наличие дубликатов в строке, столбце или поле за время O (n), а не за O (n ^ 2): при повторении набора чисел вы добавляете каждое из них в хэшсет. В зависимости от языка вы действительно можете использовать настоящий хеш-набор, который представляет собой постоянный поиск и вставку; тогда проверка дубликатов может быть выполнена на том же этапе, проверив, была ли вставка успешной или нет. Это незначительное улучшение кода, но переход от O (n ^ 2) к O (n) является значительной оптимизацией.

Другие вопросы по теме