羅塞塔網站上的c++解數獨程式

lt發表於2016-09-30

原文在這裡

#include <stdio.h>
#define N 3
int x[][N * N] = {
    { 0,0,0,0,0,0,0,1,0 },
    { 4,0,0,0,0,0,0,0,0 },
    { 0,2,0,0,0,0,0,0,0 },
    { 0,0,0,0,5,0,4,0,7 },
    { 0,0,8,0,0,0,3,0,0 },
    { 0,0,1,0,9,0,0,0,0 },
    { 3,0,0,4,0,0,2,0,0 },
    { 0,5,0,1,0,0,0,0,0 },
    { 0,0,0,8,0,6,0,0,0 }
};


#define W (N * N)

int ptr, used[W][W], bits[256];
struct { int *p, v; } rec[W * W * W * 3];

inline int countbits(int v)
{
    int c = 0;
    while (v) {
        c += bits[v & 255];
        v >>= 8;
    }
    return W - c;
}

void show()
{
    int i, j;
    for (i = 0; i < W; i++) {
        if (!(i % N)) putchar('\n');
        for (j = 0; j < W; j++)
            printf(j % N ? "%3d" : "%4d", x[i][j]);
        putchar('\n');
    }

    return;
}

void save(int *p, int v)
{
    rec[ptr].p = p, rec[ptr].v = *p;
    *p = v;
    ptr++;
}

void restore(int i)
{
    while (ptr > i) {
        --ptr;
        rec[ptr].p[0] = rec[ptr].v;
    }
}

int setcell(int row, int col, int v)
{
    int i, j, b = 1 << (v - 1), c, r;
    int cur = ptr;

    if (used[row][col] & (1 << (v - 1))) {
        restore(cur);
        return 0;
    }

    save(used[row] + col, (1 << W) - 1);
    save(x[row] + col, v);

    for (i = 0; i < W; i++)
        if (i != col && !(used[row][i] & b))
            save(used[row] + i, used[row][i] | b);

    for (i = 0; i < W; i++)
        if (i != row && !(used[i][col] & b))
            save(used[i] + col, used[i][col] | b);

    r = row / N * N;
    c = col / N * N;
    for (i = r; i < r + N; i++) {
        if (i == row) continue;
        for (j = c; j < c + N; j++)
            if (j != col && !(used[i][j] & b))
                save(used[i] + j, used[i][j] | b);
    }

    return 1;
}

int tryfill()
{
    int i, j, bi, bj, least = W + 1;
    int u, cur = ptr;

    for (i = 0; i < W; i++) {
        for (j = 0; j  < W; j++) {
            if (x[i][j]) continue;
            if (!(u = countbits(used[i][j]))) return 0;

            if (u < least) {
                least = u, bi = i, bj = j;
                if (least == 1) goto done;
            }
        }
    }

    if (least == W + 1) return 1;

done:    u = used[bi][bj];
    for (i = 0; i < W; i++) {
        if (u & (1 << i)) continue;

        setcell(bi, bj, i + 1);
        if (tryfill()) return 1;

        restore(cur);
    }
    return 0;
}

int solve()
{
    int i, j;
    for (i = 0; i < W; i++)
        for (j = 0; j < W; j++)
            if (x[i][j] && !setcell(i, j, x[i][j]))
                return 0;

    ptr = 0;
    tryfill();

    return 1;
}

void initbitcount()
{
    int v, i, b, c;
    for (v = 0; v < 256; v++) {
        for (b = 1, c = i = 0; i < 8; i++, b <<= 1)
            if (b & v) c++;
        bits[v] = c;
    }
}

int main(void)
{
    initbitcount();
    if (solve())
        show();
    else
        puts("no solution");

    return 0;
}

效率還不錯

D:\>cl /O2 sudoku_rose3.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.20506.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

sudoku_rose3.cpp
Microsoft (R) Incremental Linker Version 10.00.20506.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:sudoku_rose3.exe
sudoku_rose3.obj

D:\>timer sudoku_rose3
Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31

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

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

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

Kernel Time  =     0.015 =   14%
User Time    =     0.000 =    0%
Process Time =     0.015 =   14%
Global Time  =     0.109 =  100%

相關文章