Консультация № 175854
06.01.2010, 01:01
0.00 руб.
0 7 1
Здравствуйте, эксперты.
Имеется код программы, рабочей, которая генерирует судоку 9*9. Только один недочет - программа не проверяет столбцы 3*3 на повторяющие элементы. В общем, надо к коду приграммы как-то присоденить вот этот код:

Код:

int i_from, j_from;

for(i=0; i<size; i++)
{
for(j=0; j<size; j++)
{

if(i<3) i_from=0;
else if(i<6) i_from=3;
else i_from=6;

if(j<3) j_from=0;
else if(j<6) j_from=3;
else j_from=6;

for(;;)
{
repeated=false;
number=rand()%9+1;

for(l=i_from; l<i; l++)
for(k=j_from; k<j; k++)
if(sudoku[l][k]==number)
{
repeated=true;
break;
}
...
}


Подскажите, как это сделать?

Далее код самой программы: (спасибо эксперту amnick)
Код:

#include <time.h>
#include <iostream>
#include <stdlib.h>
using namespace std;

const int size = 9;
const int initial_mask = ~((-1) << size);

int sudoku[size][size]; // это матрица судоку
// этот массив будет использоваться для пометки проверенных чисел
// лишняя колонка позволяет избежать дополнительной проверки индекса
int check[size][size+1];


// генерируем ячейку
bool cell( int i, int j )
{
int chk = check[i][j]; // маска чисел, уже проверенных в этой ячейке
if( !chk )
return false; // на предыдущих проходах уже были проверены все числа

for(;;)
{
// генерируем число, новое для этой ячейки
int number, bit;
do {
number = rand() % size;
bit = 1 << number;
} while( !(chk & bit) );
chk &= ~bit;
++number;

// проверяем, было ли это число ранее ...
bool repeated = false;
// ... в столбце
for(int l=0; l<i; l++)
if(sudoku[l][j]==number)
{
repeated = true;
break;
}
if( repeated ) {
// number уже есть в этом стобце
if( chk == 0 ) return false; // проверены все числа
continue; // пытаемся снова
}

// ... в строке
for(int k=0; k<j; k++)
if(sudoku[i][k]==number)
{
repeated = true;
break;
}

if( repeated ) {
// number уже есть в этой строке
if( chk == 0 ) return false; // проверены все числа
continue; // пытаемся снова
}

sudoku[i][j] = number; // нашли подходящее (пока) число
check[i][j] = chk; // сохраняем маску проверенных чисел

cout << number << " ";
return true;
}

}

// генерируем строку
bool row( int i )
{
check[i][0] = initial_mask; // сброс маски для первой ячейки
int j = 0;
while( j < size ) {
if( cell( i, j )) {
// ячейка заполнена, переходим к следующей
++j;
check[i][j] = initial_mask; // сброс маски для очередной ячейки
// индекс j здесь не проверяли - помните объявление int check[size][size+1] ?
}
else {
// увы, не получилось
// возвращаемся к предыдущей ячейке и ищем для нее какое-то другое число
// будет использована ранее сохраненная маска check[][]
if( --j < 0 )
return false; // придется вернуться к предыдущей строке

// вывод отладочной информации - отслеживание возвратов
cout << endl << i << ": ";
for( int k = 0; k < j; ++k )
cout << sudoku[i][k] << " ";
}
}
cout << endl;
return true;
}

int main()
{
time_t kl;
time( &kl );
srand(kl);

int i = 0;
while( i < size ) {
cout << i << ": ";
if( row( i ))
++i;
else
if( --i < 0 ) { cout << endl << "error! << endl"; break; }
}

int j;
cout << endl;
for(i=0; i<size; i++)
{
for(j=0; j<9; j++)
cout << sudoku[i][j] << " ";
cout << endl;
}
}

Обсуждение

давно
Старший Модератор
31795
6196
06.01.2010, 12:34
общий
Иванов Андрей Владимирович:
Для начала я бы этот код
Код:
                        if(i<3) i_from=0;
else if(i<6) i_from=3;
else i_from=6;

if(j<3) j_from=0;
else if(j<6) j_from=3;
else j_from=6;

заменил бы на:
j_from= j - ( j % 3 );
i_from= i - ( i % 3 );
Так мы получили начало(левый-верхний угол) проверяемого квадрата 3х3.
Дополнительно цикл
Код:

j_from= j - ( j % 3 );
i_from= i - ( i % 3 );
// ... в строке
for(int k=0; k<size; k++)
{
ii=k % 3;//остаток от деления
jj=k / 3;//деление нацело
if(sudoku[i_form+ii][j_form+jj]==number)
{
repeated = true;
break;
}
}

Помоему где-то так.
комментарий [color=blue]// ... в строке
я оставил для того чтобы знали куда ставить[/color]
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
06.01.2010, 17:32
общий
Иванов Андрей Владимирович:
Когда я ответил на Ваш предыдущий вопрос по sudoku, то у меня возник дополнительный вопрос — а что насчет квадратов 3x3? И вот, Вы его задали.
Кстати, это необязательно должны быть квадраты или прямоугольники. Вы могли видеть в печатных изданиях разные симметричные области.
Неизвестный
06.01.2010, 19:48
общий
это ответ
Здравствуйте, Иванов Андрей Владимирович.

Изменения в программе нужны совсем небольшие. Проверка добавляется в функцию cell(). Размеры под-области задаются константами (в начале программы). При отладке я проверил, например, матрицу 6x6 с прямоугольными под-областями 3x2. Дополнительно, в конце функции main() добавлен вывод матрицы с разделителями. Для простоты, в приложении приведен код программы целиком.

Результат пары прогонов программы:
Код:
0: 9 5 7 2 1 4 6 8 3
1: 1 2 4 7 5 8 9
1: 1 2 4 7 5 8
1: 1 2 4 7 5 3 9
1: 1 2 4 7 5 3
1: 1 2 4 7 5 6 9
1: 1 2 4 7 5 6
1: 1 2 4 7 5 9
1: 1 2 4 7 5
1: 1 2 4 7 9 3 5
1: 1 2 4 7 9 3
1: 1 2 4 7 9 6 5
1: 1 2 4 7 9 6
1: 1 2 4 7 9 8 5
1: 1 2 4 7 9 8
1: 1 2 4 7 9 5
1: 1 2 4 7 9
1: 1 2 4 7 3 6 9 5
1: 1 2 4 7 3 6 9
1: 1 2 4 7 3 6 5 9
1: 1 2 4 7 3 6 5
1: 1 2 4 7 3 6
1: 1 2 4 7 3 8 9 5
1: 1 2 4 7 3 8 9
1: 1 2 4 7 3 8 5 9
1: 1 2 4 7 3 8 5
1: 1 2 4 7 3 8
1: 1 2 4 7 3 5 9
1: 1 2 4 7 3 5
1: 1 2 4 7 3 9 5
1: 1 2 4 7 3 9
1: 1 2 4 7 3
1: 1 2 4 7 8 3 9 5
1: 1 2 4 7 8 3 9
1: 1 2 4 7 8 3 5 9
1: 1 2 4 7 8 3 5
1: 1 2 4 7 8 3
1: 1 2 4 7 8 9 5
1: 1 2 4 7 8 9
1: 1 2 4 7 8 6 5 9
1: 1 2 4 7 8 6 5
1: 1 2 4 7 8 6 9 5
1: 1 2 4 7 8 6 9
1: 1 2 4 7 8 6
1: 1 2 4 7 8 5 9
1: 1 2 4 7 8 5
1: 1 2 4 7 8
1: 1 2 4 7 6 8 9 5
1: 1 2 4 7 6 8 9
1: 1 2 4 7 6 8 5 9
1: 1 2 4 7 6 8 5
1: 1 2 4 7 6 8
1: 1 2 4 7 6 3 9 5
1: 1 2 4 7 6 3 9
1: 1 2 4 7 6 3 5 9
1: 1 2 4 7 6 3 5
1: 1 2 4 7 6 3
1: 1 2 4 7 6 9 5
1: 1 2 4 7 6 9
1: 1 2 4 7 6 5 9
1: 1 2 4 7 6 5
1: 1 2 4 7 6
1: 1 2 4 7
1: 1 2 4 3 5 6 7 9
1: 1 2 4 3 5 6 7
1: 1 2 4 3 5 6 9 7
1: 1 2 4 3 5 6 9
1: 1 2 4 3 5 6
1: 1 2 4 3 5 7 9
1: 1 2 4 3 5 7
1: 1 2 4 3 5 9 7
1: 1 2 4 3 5 9
1: 1 2 4 3 5 8 9 7
1: 1 2 4 3 5 8 9
1: 1 2 4 3 5 8 7 9
1: 1 2 4 3 5 8 7
1: 1 2 4 3 5 8
1: 1 2 4 3 5
1: 1 2 4 3 9 7 5
1: 1 2 4 3 9 7
1: 1 2 4 3 9 5 7
1: 1 2 4 3 9 5
1: 1 2 4 3 9 8 5 7
1: 1 2 4 3 9 8 5
1: 1 2 4 3 9 8 7 5
1: 1 2 4 3 9 8 7
1: 1 2 4 3 9 8
1: 1 2 4 3 9 6 7 5
1: 1 2 4 3 9 6 7
1: 1 2 4 3 9 6 5 7
1: 1 2 4 3 9 6 5
1: 1 2 4 3 9 6
1: 1 2 4 3 9
1: 1 2 4 3 7 8 9 5
1: 1 2 4 3 7 8 9
1: 1 2 4 3 7 8 5 9
1: 1 2 4 3 7 8 5
1: 1 2 4 3 7 8
1: 1 2 4 3 7 5 9
1: 1 2 4 3 7 5
1: 1 2 4 3 7 9 5
1: 1 2 4 3 7 9
1: 1 2 4 3 7 6 5 9
1: 1 2 4 3 7 6 5
1: 1 2 4 3 7 6 9 5
1: 1 2 4 3 7 6 9
1: 1 2 4 3 7 6
1: 1 2 4 3 7
1: 1 2 4 3 8 7 9 5
1: 1 2 4 3 8 7 9
1: 1 2 4 3 8 7 5 9
1: 1 2 4 3 8 7 5
1: 1 2 4 3 8 7
1: 1 2 4 3 8 5 9 7
1: 1 2 4 3 8 5 9
1: 1 2 4 3 8 5 7 9
1: 1 2 4 3 8 5 7
1: 1 2 4 3 8 5
1: 1 2 4 3 8 9 5 7
1: 1 2 4 3 8 9 5
1: 1 2 4 3 8 9 7 5
1: 1 2 4 3 8 9 7
1: 1 2 4 3 8 9
1: 1 2 4 3 8 6 5 7 9
2: 3 6 8 9 7 5 4 1 2
3: 4 8 9 5 6 2 3
3: 4 8 9 5 6 2 1 3 7
4: 6 1 3 4 9 8 2 5
4: 6 1 3 4 9 8 2
4: 6 1 3 4 9 8
4: 6 1 3 4 9 7 8 5
4: 6 1 3 4 9 7 8 2 5
5: 2 7 5 1 3 8 9 4 6
6: 7 3 2 8 5 1
6: 7 3 2 8 5 9
6: 7 3 2 8 5
6: 7 3 2 8 4 1
6: 7 3 2 8 4 9
6: 7 3 2 8 4
6: 7 3 2 8
6: 7 3 2 6 4 1
6: 7 3 2 6 4 9
6: 7 3 2 6 4
6: 7 3 2 6 5 9
6: 7 3 2 6 5 1
6: 7 3 2 6 5
6: 7 3 2 6
6: 7 3 2
6: 7 3 6 8 4 9 2 5 1
7: 8 4 1 7 2 3
7: 8 4 1 7 2
7: 8 4 1 7 5 3
7: 8 4 1 7 5
7: 8 4 1 7
7: 8 4 1 6 2 3 7 9
7: 8 4 1 6 2 3 7
7: 8 4 1 6 2 3
7: 8 4 1 6 2
7: 8 4 1 6 5 3 7 9
7: 8 4 1 6 5 3 7
7: 8 4 1 6 5 3
7: 8 4 1 6 5
7: 8 4 1 6
7: 8 4 1
7: 8 4 2 6 5 1 7 9
7: 8 4 2 6 5 1 7
7: 8 4 2 6 5 1 3 9
7: 8 4 2 6 5 1 3
7: 8 4 2 6 5 1
7: 8 4 2 6 5 3 7 9
7: 8 4 2 6 5 3 7
7: 8 4 2 6 5 3
7: 8 4 2 6 5
7: 8 4 2 6
7: 8 4 2 7 5 3
7: 8 4 2 7 5 1 3 6
7: 8 4 2 7 5 1 3 9
7: 8 4 2 7 5 1 3
7: 8 4 2 7 5 1
7: 8 4 2 7 5
7: 8 4 2 7
7: 8 4 2
7: 8 4
7: 8 9 2 7 5 1 3 6 4
8: 5 4 1 6 2 3 7 9 8

Matrix:
9 5 7 | 2 1 4 | 6 8 3
1 2 4 | 3 8 6 | 5 7 9
3 6 8 | 9 7 5 | 4 1 2
------+-------+-------
4 8 9 | 5 6 2 | 1 3 7
6 1 3 | 4 9 7 | 8 2 5
2 7 5 | 1 3 8 | 9 4 6
------+-------+-------
7 3 6 | 8 4 9 | 2 5 1
8 9 2 | 7 5 1 | 3 6 4
5 4 1 | 6 2 3 | 7 9 8

**********************

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

Matrix:
4 1 5 | 9 6 7 | 8 3 2
6 3 8 | 2 5 4 | 9 1 7
9 7 2 | 3 1 8 | 5 4 6
------+-------+-------
2 4 7 | 1 9 6 | 3 5 8
3 9 6 | 5 8 2 | 1 7 4
5 8 1 | 4 7 3 | 2 6 9
------+-------+-------
1 2 9 | 6 4 5 | 7 8 3
8 6 3 | 7 2 1 | 4 9 5
7 5 4 | 8 3 9 | 6 2 1


Если есть вопросы, то спрашивайте в мини-форуме. Могу ответить сегодня до 23МСК или в понедельник.

Успехов!

Приложение:
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;

const int size = 9;
const int initial_mask = ~((-1) << size);

// В прямоугольнике шириной RW и высотой RH также не должно быть одинаковых точек
// Должно выполняться условие (RH*RW == size)
const int RH = 3, RW = size/RH;

int sudoku[size][size]; // это матрица судоку

// этот массив будет использоваться для пометки проверенных чисел
// лишняя колонка позволяет избежать дополнительной проверки индекса
int check[size][size+1];


// генерируем ячейку
bool cell( int i, int j )
{
int chk = check[i][j]; // маска чисел, уже проверенных в этой ячейке
if( !chk )
return false; // на предыдущих проходах уже были проверены все числа

for(;;)
{
// генерируем число, новое для этой ячейки
int number, bit;
do {
number = rand() % size;
bit = 1 << number;
} while( !(chk & bit) );
chk &= ~bit;
++number;

// проверяем, было ли это число ранее ...
bool repeated = false;
// ... в столбце
for(int l=0; l<i; l++)
if( sudoku[l][j] == number ) {
repeated = true;
break;
}
if( repeated ) {
// number уже есть в этом стобце
if( chk == 0 ) return false; // проверены все числа
continue; // пытаемся снова
}

// ... в строке
for(int k=0; k<j; k++)
if( sudoku[i][k] == number ) {
repeated = true;
break;
}

if( repeated ) {
// number уже есть в этой строке
__repeated:
if( chk == 0 ) return false; // проверены все числа
continue; // пытаемся снова
}

// ... в прямоугольнике RH x RW
int i_mod = i % RH; // номер текущей строки в под-области
if( i_mod ) { // для всех строк, кроме первых в под-областях
int j_from = j - j % RW;

// на несовпадение в текущей строке уже проверили,
// проверяем только вышележащие строки в под-области
for( l = i-i_mod; l < i; ++l )
for( k = 0; k < RW; ++k )
if( sudoku[l][j_from+k] == number )
goto __repeated; // некрасиво, но это простейший способ выйти из вложенных циклов
}

sudoku[i][j] = number; // нашли подходящее (пока) число
check[i][j] = chk; // сохраняем маску проверенных чисел

cout << number << " ";
return true;
}

}

// генерируем строку
bool row( int i )
{
check[i][0] = initial_mask; // сброс маски для первой ячейки
int j = 0;
while( j < size ) {
if( cell( i, j )) {
// ячейка заполнена, переходим к следующей
++j;
check[i][j] = initial_mask; // сброс маски для очередной ячейки
// индекс j здесь не проверяли - помните объявление int check[size][size+1] ?
}
else {
// увы, не получилось
// возвращаемся к предыдущей ячейке и ищем для нее какое-то другое число
// будет использована ранее сохраненная маска check[][]
if( --j < 0 )
return false; // придется вернуться к предыдущей строке

// вывод отладочной информации - отслеживание возвратов
cout << endl << i << ": ";
for( int k = 0; k < j; ++k )
cout << sudoku[i][k] << " ";
}
}
cout << endl;
return true;
}

void main()
{
time_t kl;
time( &kl );
srand(kl);

int i = 0;
while( i < size ) {
cout << i << ": ";
if( row( i ))
++i;
else
if( --i < 0 ) { cout << endl << "error! << endl"; return; }
}
cout << "\nMatrix:\n";

// формируем разделитель
char szDivider[32];
{
short* p = (short*)szDivider;
for( int j = 0; j < size; ++j ) {
if( j && j % RW == 0 )
*p++ = *(short*)"+-";
*p++ = *(short*)"--";
}
*(char*)p = 0;
}

for( i = 0; i < size; ++i ) {
if( i && i % RH == 0 )
cout << szDivider << endl;
for( int j = 0; j < size; ++j ) {
if( j && j % RW == 0 )
cout << "| ";
cout << sudoku[i][j] << " ";
}
cout << endl;
}
}
5
Неизвестный
06.01.2010, 20:15
общий
Зенченко Константин Николаевич:
Какой-то странный код Вы предложили.

Посмотрите повнимательнее на фрагмент:
Код:
for(int k=0; k<size; k++)
{
ii=k % 3;//остаток от деления
jj=k / 3;//деление нацело
if(sudoku[i_form+ii][j_form+jj]==number)
.......


Вас не смущают возможные значения [i_form+ii]? При изменении k этот код периодически обращается к еще несгенерированным строкам. (Аналогично [j_form+jj], только для столбцов).
Этот код годится для того, чтобы найти заданное число (number) в подматрице 3x3, но он никак не подходит для этой задачи — на каждом шаге нам надо проверять не всю подматрицу 3x3, а сравнивать новое число со значениями в предыдущих строках подматрицы (поиск в текущей строке уже был выполнен ранее).
Неизвестный
07.01.2010, 17:29
общий
>> amnick
Спасибо! Ваш код работает как надо. Правда мой компилятор под Linux нашел 10 ошибок но я их быстро исправил.
Вы, вероятно, пользовались компилятором с поблажками
давно
Старший Модератор
31795
6196
08.01.2010, 11:49
общий
amnick:
Почему странный?
Я не обращал внимание на механизм заполнения(как задаются строка-столбец) массива, только на механизм контроля.
А сам вопрос звучал: программа не проверяет столбцы 3*3 на повторяющие элементы.
Цитата: 307758
Этот код годится для того, чтобы найти заданное число (number) в подматрице 3x3

он так и задумывался.

Сообщения вроде:
Могу ответить сегодня до 23МСК или в понедельник.
В будущем помещайте в мини-форум, т.к. читателям рассылки это не интересно.
Удачи!
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
11.01.2010, 13:50
общий
Иванов Андрей Владимирович:
Я отлаживал код в MSVC++ 6.0
Форма ответа