Я использовал метод без обратной трассировки, хотя это может быть цикл while. Чтобы процитировать книгу алгоритмов, которую я прочитал, «Ничто в рекурсии не может быть продублировано с помощью итерации».
Я использовал свои глаза, чтобы проверить это, и, поскольку я не могу понять рекурсивный метод, хотя рекурсия относительно понятна:
Этот метод, который я как бы написал с некоторым руководством, имел ошибку в проверке сетки, когда я ее нашел, теперь она работает. Я утверждаю это, потому что трудно найти полный и работающий код. SDK для iOS.
#define WIDTH 9
#define HEIGHT 9
@interface ViewController ()
//- (BOOL) numberConflicts:(int)testNum;
- (BOOL) number:(int)n conflictsWithRow:(int)r;
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
- (int) incrementSudokuValue:(int)v;
@end
static int sudoku[WIDTH][HEIGHT];
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/// Initialize it
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
sudoku[x][y] = 0;
}
}
///
int tries = 0;
for (int j = 0; j < HEIGHT; j++)
{
for (int i = 0; i < WIDTH; i++)
{
int num = arc4random()%9 + 1;
while ([self number:num conflictsAtGridPointX:i andPointY:j])
{
num = [self incrementSudokuValue:num];
tries++;
if (tries > 10) { //restart the column
tries = 0;
for(int count = 0; count < WIDTH; count++)
{
sudoku[count][j] = 0;
}
i = 0;
}
}
if(sudoku[i][j] == 0)
sudoku[i][j] = num;
tries = 0;
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
printf("%i ", sudoku[x][y]);
}
printf("\n");
}
printf("\n");
}
}
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
printf("%i ", sudoku[y][x]);
}
printf("\n"); //newline
}
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) number:(int)n conflictsWithRow:(int)r;
{
for (int y = 0; y < HEIGHT; y++) {
if (sudoku[y][r] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
{
for (int x = 0; x < WIDTH; x++) {
if (sudoku[c][x] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
{
if ([self number:n conflictsWithRow:yPoint])
{
return YES;
}
if ([self number:n conflictsWithColumn:xPoint])
{
return YES;
}
if ([self number:n conflictsWithSquareInPointX:xPoint andPointY:yPoint]) {
return YES;
}
return NO;
}
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
{
int leftX = x - (x % 3); //used to use int division
// leftX *= 3;
int topY = y - (y % 3);
// topY *= 3;
int rightX = leftX + 2;
int bottomY = topY + 2;
for(int subY = topY; subY <= bottomY; subY++) //bug was here, used < instead of less N equal to...
{
for ( int subX = leftX; subX <= rightX; subX++)
{
if (sudoku[subX][subY] == n) {
return YES;
}
}
}
NSLog(@"Testing grid at %i, %i", x/3, y/3);
NSLog(@"LeftX: %i TopY: %i", leftX, topY);
return NO;
}
- (int) incrementSudokuValue:(int)v;
{
if (v < 9) {
v++;
return v;
}
return 1;
}
Примечание. Файл заголовка пуст, вставьте его в приложение iOS single View, если хотите.
Предупреждение: может быть бесконечный цикл (иногда это происходит, но очень быстро), может потребоваться еще одна более глобальная переменная «попытки» и перезапустить алгоритм в качестве безопасности или дать ему семя / сделать и то, и другое.
редактировать: ниже должно быть безопасно от бесконечных циклов, если исходная сетка разрешима (или не существует)
#define WIDTH 9
#define HEIGHT 9
@interface ViewController ()
//- (BOOL) numberConflicts:(int)testNum;
- (BOOL) number:(int)n conflictsWithRow:(int)r;
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
- (int) incrementSudokuValue:(int)v;
@end
static int sudoku[WIDTH][HEIGHT];
@implementation ViewController
- (BOOL) fillGridWithNext:(int)next;
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
if (sudoku[x][y] != 0)
{
if (x == 8 && y == 8) {
return YES;
}
continue;
}
for (int count = 0; count < (HEIGHT-1); count++)
{
if ([self number:next conflictsAtGridPointX:x andPointY:y])
{
next = [self incrementSudokuValue:next];
}
else
{
sudoku[x][y] = next;
if( [self fillGridWithNext:arc4random()%9+1])
{
return YES;
}
}
}
sudoku[x][y] = 0;
return NO;
}
}
return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
/// Initialize it
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
sudoku[x][y] = 0;
}
}
sudoku[0][0]=9;
int next;
next = (arc4random()%9)+1;
if( [self fillGridWithNext:next]) //seeded
{
NSLog(@"Solved");
}
else
{
NSLog(@"No solution");
}
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
printf("%i ", sudoku[y][x]);
}
printf("\n"); //newline
}
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) number:(int)n conflictsWithRow:(int)r;
{
for (int y = 0; y < HEIGHT; y++) {
if (sudoku[y][r] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
{
for (int x = 0; x < WIDTH; x++) {
if (sudoku[c][x] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
{
if ([self number:n conflictsWithRow:yPoint])
{
return YES;
}
if ([self number:n conflictsWithColumn:xPoint])
{
return YES;
}
if ([self number:n conflictsWithSquareInPointX:xPoint andPointY:yPoint]) {
return YES;
}
return NO;
}
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
{
int leftX = x - (x % 3); //used to use int division
// leftX *= 3;
int topY = y - (y % 3);
// topY *= 3;
int rightX = leftX + 2;
int bottomY = topY + 2;
for(int subY = topY; subY <= bottomY; subY++) //bug was here, used < instead of less N equal to...
{
for ( int subX = leftX; subX <= rightX; subX++)
{
if (sudoku[subX][subY] == n) {
return YES;
}
}
}
NSLog(@"Testing grid at %i, %i", x/3, y/3);
NSLog(@"LeftX: %i TopY: %i", leftX, topY);
return NO;
}
- (int) incrementSudokuValue:(int)v;
{
if (v < 9) {
v++;
return v;
}
return 1;
}
@end
Резюме: первая версия имеет недостатки, но (в основном) выполняет свою работу. Он генерирует каждую строку случайным образом, если строка недействительна, она стирается и начинается заново. Это уничтожит исходные сетки и может продолжаться вечно, но работает в большинстве случаев.
Нижний код использует рекурсию. Я не думаю, что он откатывается должным образом, но в моих тестах он решал пустые и полузаполненные сетки. Я думаю, что мне нужно сохранить сетку «состояния», чтобы вернуться, но я этого не делаю. Я публикую оба, так как они оба отвечают на "Грубую силу"... сам по себе, я должен изучить рекурсию, я не могу объяснить, почему нижний работает, мне лично не помешала бы помощь в этом.
Примечание. Первый из них завершается в мгновение ока или около того, когда он завершается... если скорость означает больше, чем надежность для вашего приложения (в этом случае несколько нелогично, с бесконечным циклом, хех).
person
Stephen J
schedule
21.11.2012