|
| 1 | +#include <stdio.h> |
| 2 | +#include "pico/stdlib.h" |
| 3 | +#include <stdio.h> |
| 4 | +#include <stdint.h> |
| 5 | +#include <stdlib.h> |
| 6 | +#include <string.h> |
| 7 | +#include <unistd.h> |
| 8 | +#include <time.h> |
| 9 | +#include <sys/time.h> |
| 10 | + |
| 11 | + |
| 12 | +#define boardSize 15 |
| 13 | +#define MAXN 31 |
| 14 | + |
| 15 | +int nqueens(int n) |
| 16 | +{ |
| 17 | + int q0, q1; |
| 18 | + int cols[MAXN], diagl[MAXN], diagr[MAXN], posibs[MAXN]; // Our backtracking 'stack' |
| 19 | + int num = 0; |
| 20 | + // |
| 21 | + // The top level is two fors, to save one bit of symmetry in the enumeration by forcing second queen to |
| 22 | + // be AFTER the first queen. |
| 23 | + // |
| 24 | + for (q0 = 0; q0 < n - 2; q0++) |
| 25 | + { |
| 26 | + for (q1 = q0 + 2; q1 < n; q1++) |
| 27 | + { |
| 28 | + int bit0 = 1 << q0; |
| 29 | + int bit1 = 1 << q1; |
| 30 | + int d = 0; // d is our depth in the backtrack stack |
| 31 | + cols[0] = bit0 | bit1 | (-1 << n); // The -1 here is used to fill all 'coloumn' bits after n ... |
| 32 | + diagl[0] = (bit0 << 1 | bit1) << 1; |
| 33 | + diagr[0] = (bit0 >> 1 | bit1) >> 1; |
| 34 | + |
| 35 | + // The variable posib contains the bitmask of possibilities we still have to try in a given row ... |
| 36 | + int posib = ~(cols[0] | diagl[0] | diagr[0]); |
| 37 | + |
| 38 | + while (d >= 0) |
| 39 | + { |
| 40 | + while (posib) |
| 41 | + { |
| 42 | + int bit = posib & -posib; // The standard trick for getting the rightmost bit in the mask |
| 43 | + int ncols = cols[d] | bit; |
| 44 | + int ndiagl = (diagl[d] | bit) << 1; |
| 45 | + int ndiagr = (diagr[d] | bit) >> 1; |
| 46 | + int nposib = ~(ncols | ndiagl | ndiagr); |
| 47 | + posib ^= bit; // Eliminate the tried possibility. |
| 48 | + |
| 49 | + // The following is the main additional trick here, as recognizing solution can not be done using stack level (d), |
| 50 | + // since we save the depth+backtrack time at the end of the enumeration loop. However by noticing all coloumns are |
| 51 | + // filled (comparison to -1) we know a solution was reached ... |
| 52 | + // Notice also that avoiding an if on the ncols==-1 comparison is more efficient! |
| 53 | + num += ncols == -1; |
| 54 | + |
| 55 | + if (nposib) |
| 56 | + { |
| 57 | + if (posib) |
| 58 | + { // This if saves stack depth + backtrack operations when we passed the last possibility in a row |
| 59 | + posibs[d++] = posib; // Go lower in stack .. |
| 60 | + } |
| 61 | + cols[d] = ncols; |
| 62 | + diagl[d] = ndiagl; |
| 63 | + diagr[d] = ndiagr; |
| 64 | + posib = nposib; |
| 65 | + } |
| 66 | + } |
| 67 | + posib = posibs[--d]; // backtrack ... |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | + return num * 2; |
| 72 | +} |
| 73 | + |
| 74 | +int main() |
| 75 | +{ |
| 76 | + stdio_init_all(); |
| 77 | + printf("Init...\n"); |
| 78 | + stdio_flush(); |
| 79 | + sleep_ms(5000); |
| 80 | +#if PICO_RP2350 |
| 81 | + printf("I'm an RP2350 "); |
| 82 | + #ifdef __riscv |
| 83 | + printf("running RISC-V\n"); |
| 84 | + #else |
| 85 | + printf("running ARM\n"); |
| 86 | + #endif |
| 87 | +#endif |
| 88 | + printf("Start...\n"); |
| 89 | + stdio_flush(); |
| 90 | + |
| 91 | + clock_t startt = clock(); |
| 92 | + printf("Started at %u\n", startt); |
| 93 | + int n = nqueens(boardSize); |
| 94 | + printf("Total solutions: %d\n", n); |
| 95 | + clock_t endt = clock(); |
| 96 | + printf("Ended at %u\n", endt); |
| 97 | + printf("%d\n", (int)(endt - startt)); |
| 98 | + for (;;) |
| 99 | + { |
| 100 | + sleep_ms(10000); |
| 101 | + } |
| 102 | +} |
0 commit comments