Google Kickstart 2013 Round B Проблема Средство проверки судоку дает неправильный ответ, но работает

https://codingcompetitions.withgoogle.com/kickstart/round/0000000000434ad7/00000000004347b >
Судоку - популярная одиночная игра. Цель состоит в том, чтобы заполнить матрицу 9x9 цифрами так, чтобы каждый столбец, каждая строка и все 9 неперекрывающихся субматриц 3x3 содержали все цифры от 1 до 9. Каждая матрица 9x9 частично заполнялась в начале игры. и обычно имеет уникальное решение.
Имея заполненную матрицу судоку N2xN2, ваша задача - определить, является ли это правильным решением. Действительное решение должно удовлетворять следующим критериям:

Каждая строка содержит каждое число от 1 до N2, по одному разу.
Каждый столбец содержит каждое число от 1 до N2, по одному разу.
Разделите матрицу N2xN2 на N2 неперекрывающихся подматриц NxN. Каждая подматрица содержит каждое число от 1 до N2, по одному разу.

Мой код:

 #include <iostream>
 using namespace std;


 int main()
{
int i, j, k, no, n, sum, t[36][36], validsum;
cin >> no;
for (k = 0; k < no; k++)
{
    cin >> n;

    for (i = 0; i < n * n; i++)
    {
        for (j = 0; j < n * n; j++)
        {
            cin >> t[i][j];
        }
    }

    bool valid = 1;
    
    validsum = ((n*n)*(n*n+1))/2;
    sum = 0;

    if (valid == 1)
    {
        for (i = 0; (i < n * n) && valid == 1; i++)
        {
            sum = 0;
            for (j = 0; (j < n * n) && sum < validsum; j = j+1) {
                sum += t[i][j];
            }
            if (sum != validsum)
                valid = 0;
        }
    }

    if (valid == 1)
    {
        for (j = 0; j < n * n && valid == 1; j++)
        {
            sum = 0;
            for (i = 0; i < n * n && sum < validsum; i++)
            {
                sum += t[i][j];
            }
            if (sum != validsum)
                valid = 0;
        }
    }

    cout << "Case #" << k + 1 << ": ";
    if (valid == 1)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
}
}

Мои результаты:

Case #1: Yes
Case #2: No
Case #3: No

Примеры результатов:

Case #1: Yes
Case #2: No
Case #3: No

Это потому, что это недостаточно быстро?


person Dani Suba    schedule 22.03.2021    source источник
comment
Всего 3 случая? Или есть еще случаи?   -  person user253751    schedule 22.03.2021
comment
Подсказка: ваш код неверен. В некоторых случаях он дает неправильный ответ.   -  person user253751    schedule 22.03.2021
comment
Этот сайт указывает, если вы потерпели неудачу из-за неправильного ответа (WA) или из-за того, что он слишком медленный (TLE). Какое сообщение вы получили?   -  person Damien    schedule 22.03.2021
comment
Я получил сообщение о неправильном ответе   -  person Dani Suba    schedule 22.03.2021
comment
Можете ли вы представить себе случай, когда ваша программа дает неправильный ответ? Я могу.   -  person user253751    schedule 22.03.2021
comment
Вы не проверяете подматрицы. Вот пример, с которым вы можете работать: wandbox.org/permlink/bZIwsEbAeXAU2dhf Ожидаемый результат - No.   -  person    schedule 22.03.2021
comment
Недостаточно проверить суммы. 2 + 2 = 1 + 3 например.   -  person Damien    schedule 22.03.2021
comment
Я добавил второй пример относительно правильного комментария Дэмиена: wandbox.org/permlink/jXi2UnomkH4WkBJ4 Оба ожидаемых результата No но ваш код возвращает Yes в обоих тестах.   -  person    schedule 22.03.2021
comment
Всем спасибо за ответы!   -  person Dani Suba    schedule 22.03.2021


Ответы (2)


Как упоминалось в @jabaa, вы забыли проверить подматрицы.

Более того, проверки сумм недостаточно, как например 1 + 3 = 2 + 2.

Эффективное решение состоит в проверке в каждой строке, столбце или подматрице, чтобы ни одно число не приходило дважды.

Это эффективно при условии, что сначала нужно проверить, что все числа находятся в хорошем диапазоне [1, n^2]

#include <iostream>
#include <vector>

bool check_line (int sudo[36][36], const int &n, const int &n2, const int &line) {
    std::vector<int> vali(n2 + 1, 0);
    for (int i = 0; i < n2; i++) {
        int num = sudo [line][i];
        if (vali[num]) return false;
        vali[num] = 1;
    }
    return true;
}

bool check_col (int sudo[36][36], const int &n, const int &n2, const int &col) {
    std::vector<int> vali(n2 + 1, 0);
    for (int i = 0; i < n2; i++) {
        int num = sudo [i][col];
        if (vali[num]) return false;
        vali[num] = 1;
    }
    return true;
}

//  line and col represent the position of the first cell of the submatrix
bool check_sub_matr (int sudo[36][36], const int &n, const int &n2, const int &line, const int &col) {
    std::vector<int> vali(n2 + 1, 0);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            int num = sudo [line+i][col+j];
            if (vali[num]) return false;
            vali[num] = 1;
        }
    }
    return true;
}

bool validity (int sudo[36][36], const int& n, const int& n2) {
    // First check validity of numbers
    for (int i = 0; i < n2; i++) {
        for (int j = 0; j < n2; j++) {
            int number = sudo[i][j];
            if ((number < 1) || (number > n2)) return false;
        }
    }
    // Check lines
    for (int i = 0; i < n2; i++) {
        auto check = check_line (sudo, n, n2, i);
        if (!check) return false;
    }
    // Check columns
    for (int i = 0; i < n2; i++) {
        auto check = check_col (sudo, n, n2, i);
        if (!check) return false;
    }
    // Check sub-matrices
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; ++j) {
            auto check = check_sub_matr (sudo, n, n2, i*n, j*n);
            if (!check) return false;
        }
    }   
    return true;
}

int main() {
    int sudo[36][36];
    int nt;
    std::cin >> nt;
    
    for (int t = 1; t <= nt; ++t) {
        int n, n2;
        std::cin >> n;
        n2 = n*n;
        for (int i = 0; i < n2; i++) {
            for (int j = 0; j < n2; j++) {
                std::cin >> sudo[i][j];
            }
        }
        auto valid = validity (sudo, n, n2);
        std::cout << "Case #" << t << ": ";
        if (valid) std::cout << "Yes" << std::endl;
        else std::cout << "No" << std::endl;
    }
    return 0;
}
person Damien    schedule 22.03.2021

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

3
3
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5
3
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
8 5 9 7 6 1 4 2 3
1 9 8 3 4 2 5 6 7
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
3
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
2 8 8 3 4 2 5 6 7
7 6 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9

Ваш код возвращает Yes в обоих случаях, но ожидаемый результат - No в обоих случаях.

person Community    schedule 22.03.2021
comment
Это также может быть 5 5 5 5 5 5 5 5 5, 5 5 5 5 5 5 5 5 5, ..... Все в сумме дает 45, поэтому оно должно быть действительным! - person user253751; 22.03.2021
comment
@ user253751 Да, именно это я имел в виду под вы не можете проверить с помощью суммы - person ; 22.03.2021
comment
5 5 5 5 5 5 5 5 5 5 более очевидно сломан, намного проще, чем пытаться обнаружить дубликаты в ваших примерах - person user253751; 22.03.2021
comment
@ user253751 Да, ты прав. Это очень ясно демонстрирует проблему. - person ; 22.03.2021