Как придумать такие решения? (Чтобы проверить, действительна ли судоку)

https://oj.leetcode.com/problems/valid-sudoku/ Проблема должен был определить, является ли судоку действительным или нет

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

  1. В каждой строке числа от 1 до 9 должны встречаться только один раз.

  2. В каждом столбце числа от 1 до 9 должны встречаться только один раз.

  3. А числа от 1 до 9 должны встречаться только один раз в каждом из 9 подблоков сетки.

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

class Solution {
public:
    bool isValidSudoku(vector<vector<char> > &board) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        map<char, bool> row;
        map<char, bool> col;
        map<char, bool> block;

        for (int i=0;i<9;i++){
            col.clear();
            row.clear();
            for (int j=0;j<9;j++){
                if (board[i][j]!='.'){
                    if (col[board[i][j]]){
                        return false;
                    }else{
                        col[board[i][j]]=true;
                    }
                }
                if (board[j][i]!='.'){
                    if (row[board[j][i]]){
                        return false;
                    }else{
                        row[board[j][i]]=true;
                    }
                }
            }
        }

        for (int ii=0;ii<9;ii=ii+3){
            for (int jj=0;jj<9;jj=jj+3){
                block.clear();
                for (int i=ii;i<ii+3;i++){
                    for (int j=jj;j<jj+3;j++){
                        if (board[i][j]!='.'){
                            if (block[board[i][j]]){
                                return false;
                            }else{
                                block[board[i][j]]=true;
                            }
                        }
                    }
                }       
            }
        }

        return true;
    }
};

Однако позже я просмотрел некоторые коды и нашел это:

Class Solution
    {public:
        bool isValidSudoku(vector<vector<char> > &board) {
            // Start typing your C/C++ solution below
            // DO NOT write int main() function
            vector<vector<bool> > rows(9, vector<bool>(9, false));
            vector<vector<bool> > cols(9, vector<bool>(9, false));
            vector<vector<bool> > blocks(9, vector<bool>(9, false));

            for (int i = 0; i < 9; ++i) {
                for (int j = 0; j < 9; ++j) {
                    if (board[i][j] == '.') continue;
                    int c = board[i][j] - '1';
                    if (rows[i][c] || cols[j][c] || blocks[i - i % 3 + j / 3][c])
                        return false;
                    rows[i][c] = cols[j][c] = blocks[i - i % 3 + j / 3][c] = true;
                }
            }
            return true;
        }

    };

Как вы можете видеть, это довольно аккуратное решение, но поразительной частью для меня было «блоки [i - i % 3 + j / 3] [c]». Мой вопрос в том, как вы делаете такое выражение «i - i % 3 + j / 3" для подмассива? Насколько мне известно, не существовало общей формулы для доступа к матрице 3X3 из 9x9. Если бы кто-то мог дать общие правила для создания таких аккуратных кодов, я был бы более чем счастлив.


person swapedoc    schedule 30.05.2014    source источник
comment
Вы понимаете оператор модуля?   -  person Thomas Matthews    schedule 31.05.2014
comment
Да. Я просто не понимаю, как он придумал формулу   -  person swapedoc    schedule 31.05.2014
comment
Кстати, подумайте об обучении на Topcoder или USACO. После нескольких недель тренировок это покажется вам очень легкой задачей.   -  person polkovnikov.ph    schedule 31.05.2014


Ответы (1)


Мы хотели бы получить функцию от (row, col) до номера блока. Вот карта результатов, которые мы хотели бы видеть

000 111 222
000 111 222
000 111 222
333 444 555
333 444 555
333 444 555
666 777 888
666 777 888
666 777 888

Посмотрим на первую строчку. Такие повторяющиеся структуры происходят от целочисленного деления. Итак, если вы попробуете col / 3, вы получите именно первую строку.

Теперь давайте посмотрим на всю таблицу. Давайте вычтем это первое выражение из всех строк, чтобы оно показало все A[row][col], такие что A[row][col] + col / 3 = block_no.

000 000 000
000 000 000
000 000 000
333 333 333
333 333 333
333 333 333
666 666 666
666 666 666
666 666 666

Эй, это больше не зависит от номера столбца. Если вы разделите это на 3, вы увидите структуру, с которой мы только что работали, и решите, что вам нужно row / 3.

Итак, все вместе: col / 3 + 3 * (row / 3).

Часть справа очень похожа на операцию «округлить до ближайшего кратного 3». Этого можно добиться и другим способом: вы можете вычесть все, что больше этого ближайшего кратного. Это именно то, что делает оператор модуля. Таким образом, мы можем упростить его до

col / 3 + row - row % 3.

person polkovnikov.ph    schedule 30.05.2014