Search code examples
calgorithmn-queens

Implementing Backtracking N-Queens Algorithm


I am implementing an algorithm in C to solve the N-Queens problem. My code solves the problem for n = 4, but doesn't work for any other values of n. I think the issue may be in the print code, but I am unsure. I've tried changing the conditions in the for loops, but haven't found anything that works. I also need to find the number of nodes pruned from the solution tree while solving. How do I go about fixing this and finding the pruned node count?

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

int count = 0;

void queens(int n, int row, int col[]);
int promising(int row, int col[]);
void usage(char *argv);

int main(int argc, char *argv[])
{    
    if (argc < 2) { usage(argv[0]); }
    int n = atoi(argv[1]);
    int col[n];
    queens(n, 0, col);
}

void queens(int n, int row, int *col)
{
    int index;

    if (promising(row, col))
    {
        if (row == n)
        {
            printf("\nSolution %d\n------------\n", ++count);
            for (int i = 1; i <= n; i++, putchar('\n')) // This works for n = 4.            
            {
                for (int j = 0; j <= n - 1; j++) // This works for n = 4.
                {                    
                    if (j == col[i]) { putchar('Q'); }
                    else { putchar('*'); }
                }
            }
            return;
        }
        else
        {
            for (index = 0; index < n; index++)
            {
                col[row + 1] = index;
                queens(n, row + 1, col);
            }
        }
    }
}

int promising(int row, int *col)
{
    int index;
    int is_promising;

    index = 0;
    is_promising = 1;
    while (index < row && is_promising)
    {
        if (col[row] == col[index] || abs(col[row] - col[index]) == row - index)
        {
            is_promising = 0;
        }
        index++;
    }
    return is_promising;
}

void usage(char *argv)
{
    printf("usage: %s <number of queens>", argv);
    exit(0);
}

Solution

  • There are multiple problems in you code:

    You are not systematic enough about index ranges: you use 0 to n and 1 to n-1, inclusive or exclusive (operators <= and <) confusing the reader... and invoking undefined behaviour when accessing cols[n]. As a rule of thumb: In C, where there is a <=, there is a bug.

    You are not testing for termination correctly in the queens function: instead of testing for termination before enumerating all possible columns for the current row, you test for adequation first: as a consequence, you miss all solutions where there is no queen in cell A1.

    Here is a corrected and simplified version:

    #include <stdio.h>
    #include <stdlib.h>
    
    static int count = 0;
    
    static int promising(int row, int *col) {
        for (int i = 0; i < row; i++) {
            if (col[row] == col[i] || abs(col[row] - col[i]) == row - i) {
                return 0;
            }
        }
        return 1;
    }
    
    static void queens(int n, int row, int *col) {
        if (row == n) {
            printf("\nSolution %d\n------------\n", ++count);
            for (int i = 0; i < n; i++, putchar('\n')) {
                for (int j = 0; j < n; j++) {
                    putchar("*Q"[j == col[i]]);
                }
            }
        } else {
            for (int i = 0; i < n; i++) {
                col[row] = i;
                if (promising(row, col)) {
                    queens(n, row + 1, col);
                }
            }
        }
    }
    
    void usage(const char *argv) {
        printf("usage: %s <number of queens>", argv);
        exit(0);
    }
    
    int main(int argc, char *argv[]) {
        if (argc < 2) { usage(argv[0]); }
        int n = atoi(argv[1]);
        int col[n];
        queens(n, 0, col);
    }
    

    The algorithm uses brute force, you still have work to do to compute pruned nodes etc.