简体   繁体   中英

Sudoku 9 boxes ( 3x3 ) Recursion Backtracking in C all combinations

I wrote a sudoku for 3x3 ( 9 boxes ) I want to make it recursive and generate all the combinations but I don't know where I went wrong ... Here is my code:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define dbg 0
using namespace std; 
int n,st[100][100];

void afisare()
{
    for(int i=1;i<=3;i++) {
        for(int j=1;j<=3;j++)
            printf("%2d",st[i][j]);

        printf("\n");
    }

    printf("\n");
}

int valid(int k,int ii,int jj)
{
    int i,j;
//  if(k==1){
//      if(dbg)printf("\nReturnez 1 deoarece k-ul este egal cu 1");
//  return 1;
//  }

    for(i=1;i<=3;i++)
        for(j=1;j<=3;j++)
            if((i==ii) && (j==jj))
            {
                if(dbg)
                    printf("\nValorile nu indeplinesc criteriul, se incrementeaza j.");
            }
            else
            {
                if(dbg)
                    printf("\n i= %d j= %d",i,j);

                if(dbg)
                    printf("\nSe verifica daca %d este egal cu casuta %d %d",k,i,j);

                if(k==st[i][j]) {
                    if(dbg)printf("\nValorile sunt egale, returnez 0");
                    return 0;
                }
            }

    if(dbg)
        printf("\nValorile nu sunt egale, deci returnez 1");

    return 1;
} 

void back(int k)
{
    int i,j;

    if(dbg) printf("\nk=",k);

    for(i=1;i<=3;i++) {
        for(j=1;j<=3;j++)
        {
            if(dbg)
                printf("\nVerifica daca casuta %d %d este egal cu 0",i,j);

            if(st[i][j]==0) {
                if(dbg) printf("\n Este egal cu 0");
                if(dbg) printf("\n%d ia valoarea %d.",st[i][j],k);

                st[i][j]=k;

                if(dbg)
                    printf("\nSe verifica valabilitatea numarului %d",st[i][j]);

                // while(valid(k,i,j)!=0)
                if(valid(k,i,j)!=0) {
                    valid(++k,i,j);
                    //back(k+1);
                }
                else
                    do {
                        st[i][j]=k+1;
                        if(dbg)
                            printf("\nCasuta %d %d are noua valoare %d, veche valoare fiind %d.",i,j,k+1,k);    
                        if(dbg)
                            ("\nValoarea returnata este 0, merg cu urmatoarea valoare %d si verific valabilitatea.",k+1);

                        //back(k+1);
                    }
                    while(valid(++k,i,j)==0);
            }
            else
                if(dbg)
                    printf("\nNu este egala cu 0 ci are valoarea %d",st[i][j]);
        }
    }

    if(k>9 || st[3][3]!=0)
        afisare();

    //afisare();
}

int main()
{
    int i,j;
    freopen("sudoku.in","r",stdin);

    for(i=1;i<=3;i++)
        for(j=1;j<=3;j++)
            scanf("%d",&st[i][j]);

/*  for(i=1;i<=3;i++){
        for(j=1;j<=3;j++){
            printf("%2d",st[i][j]);
        }

        printf("\n");
    }*/

    back(1);
    system("pause");

    return 0;
}

As I said I don't know how to generate all combinations, I only think I should call the function backtracking not the valid ...

The issue with your code is mainly to do formatting, and naming things. You have probably managed to confuse yourself by naming the recursive function back , and here's why:

Recursive solutions to problems that require you to find all solutions for a given starting condition, are basically doing a Depth First Search in the solution space. This means each recursive call is a forward movement.

You do not backtrack by calling a method, you backtrack by not calling the forward method anymore, to allow the DFS tree (which the recursion is traversing down one path of) to move back up the path it was looking in.

In your case, you are using a global data structure ( st ) to store your sudoku grid though. Which means, when you are going to backtrack, you need to return the state of the grid to how it was before you called the method. In your case, this means setting the position you were checking in to 0 again.

Here's a guide to the solution, and the way I would solve it, (if I were using a global data structure, which by the way, is not very good programming practice. I would recommend using a class to store the grid).

Firstly, some name changes:

  • void afisare() will be void printGrid() in my solution (the implementation will be the same)
  • int valid(int, int, int) will be bool isValid(int, int, int) , and it can be simplified.
  • void back(int) will be void fillEmpty()

    This function will try filling the next empty space with all possible numbers, and for all valid numbers, it will recurse down and call fillEmpty() again. If there are no empty numbers left, it will print the grid, because you've found a solution.

So here's the solution to your problem, as I understood it.

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int grid[3][3];

void
printGrid()
{
    for(int i = 0; i < 3; ++i) {

        for(int j = 0; j < 3; ++j)
            printf("%d ", grid[i][j]);

        printf("\n");
    }

    printf("\n");
}

bool
isValid(int k, int ii, int jj)
{
    for(int i = 0; i < 3; ++i)
        for(int j = 0; j < 3; ++j) {
            if( (i != ii || j != jj) && grid[i][j] == k)
                return false;
        }

    return true;
}

void 
fillEmpty()
{
    // Find the next empty position.
    int i, j; bool foundEmpty = false;
    for(i = 0; i < 3; ++i) {
        for(j = 0; j < 3; ++j)
            if(grid[i][j] == 0) {
                foundEmpty = true;
                break;
            }

        if(foundEmpty) break;
    }

    // If there are no empty positions left
    // we have reached a solution, so we
    // print it and do nothing else.
    if(!foundEmpty)
    {
        printGrid();
        return;
    }

    // Try every number
    for(int k = 1; k <= 9; ++k)
        if( isValid(k, i, j) )
        {
            grid[i][j] = k;
            fillEmpty();
        }

    // Reset the grid position before backtracking.
    grid[i][j] = 0;
}

int 
main(void)
{
    for(int i = 0; i < 3; ++i)
        for(int j = 0; j < 3; ++j)
            scanf("%d", &grid[i][j]);

    printGrid();
    fillEmpty();

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM