画圆的沙滩

亦简亦美

数独

这是求解数独的程序。还是深搜。

class Sudoku {
    int table[9][9];
    bool occupied[9][9][9];
    int solution[9][9];

public:
    Sudoku(int* tab = 0) {
        set(tab);
    }

    void set(int* tab) {
        if (!tab) return;
        for (int i = 0; i < 81; ++i)
            table[i/9][i%9] = tab[i];

        init();
    }

    int solve() {
        int cnt = 0;
        solve(count(), cnt);
        return cnt;
    }

    bool solved() {
        bool r = true;
        for (int i = 0; r && i < 9; ++i)
            for (int j = 0; r && j < 9; ++j)
                if (!solution[i][j]) r = false;

        return r;
    }

    bool valid() {
        int i, j;
        return select(i, j);
    }

    void print(ostream& os) {
        for (int i = 0; i < 9; ++i) {
            if (!(i%3))
                os<<"-------------------------\n";
            for (int j = 0; j < 9; ++j) {
                if (!(j%3))
                    os<<"| ";
                os<<solution[i][j]<<' ';
            }
            os<<"|\n";
        }
        os<<"-------------------------\n";
    }

private:
    int count() {
        int n = 0;
        for (int i = 0; i < 9; ++i)
            for (int j = 0; j < 9; ++j)
                if (!table[i][j]) ++n;

        return n;
    }

    bool solve(int n, int& cnt) {
        if (!n) {
            ++cnt;
            for (int i = 0; i < 9; ++i)
                for (int j = 0; j < 9; ++j)
                    solution[i][j] = table[i][j];
            return true;
        }
        if (cnt > 1) return true;

        int i = -1, j = -1;
        if (select(i, j)) {
            bool oldvalue[9][9];
            for (int k = 0; cnt < 2 && k < 9; ++k) {
                if (occupied[i][j][k]) continue;

                table[i][j] = k + 1;
                update(i, j, true, oldvalue);
                solve(n-1, cnt);
                update(i, j, false, oldvalue);
            }
            table[i][j] = 0;
        }

        return cnt > 0;
    }

    void update(int i, int j, bool value, bool oldvalue[][9]) {
        if (value) {
            for (int ii = 0; ii < 9; ++ii)
                for (int jj = 0; jj < 9; ++jj)
                    oldvalue[ii][jj] = occupied[ii][jj][table[i][j]-1];

            for (int k = 0; k < 9; ++k) {
                occupied[i][k][table[i][j]-1] = value;
                occupied[k][j][table[i][j]-1] = value;
            }

            int gi = i/3, gj = j/3;
            for (int p = 0; p < 3; ++p) {
                int iii = gi*3 + p;
                for (int q = 0; q < 3; ++q) {
                    int jjj = gj*3 + q;
                    occupied[iii][jjj][table[i][j]-1] = value;
                }
            }
        }
        else {
            for (int ii = 0; ii < 9; ++ii)
                for (int jj = 0; jj < 9; ++jj)
                    occupied[ii][jj][table[i][j]-1] = oldvalue[ii][jj];
        }
    }

    int occupy(int i, int j) {
        int cmin = 0;
        for (int k = 0; k < 9; ++k)
            if (!occupied[i][j][k]) ++cmin;
        return cmin;
    }

    bool select(int& i, int& j) {
        int min = 10, mini, minj;

        for (int ii = 0; ii < 9; ++ii) {
            for (int jj = 0; jj < 9; ++jj) {
                if (table[ii][jj]) continue;

                int cmin = occupy(ii, jj);
                if (!cmin) return false;

                if (cmin < min) {
                    min = cmin;
                    mini = ii;
                    minj = jj;
                }
            }
        }

        if (min < 10) {
            i = mini;
            j = minj;
            return true;
        }
        return false;
    }

    void init() {
        for (int i = 0; i < 9; ++i)
            for (int j = 0; j < 9; ++j) {
                for (int k = 0; k < 9; ++k)
                    occupied[i][j][k] = false;
                solution[i][j] = 0;
            }

        bool oldvalue[9][9];
        for (int i = 0; i < 9; ++i)
            for (int j = 0; j < 9; ++j)
                if (table[i][j])
                    update(i, j, true, oldvalue);
    }
};

int main() {
    Sudoku sudoku;
    int table[81];
    while (1) {
        bool in = true;
        int i = 0;
        for (; in && i < 81; ++i)
            in = !!(cin>>table[i]);
        if (!in || i < 81) break;
        sudoku.set(table);

        if (sudoku.valid()) {
            int cnt = sudoku.solve();
            if (cnt == 1)
                sudoku.print(cout);
            else if (cnt == 0)
                cout<<"Case not solvable.\n";
            else
                cout<<"Case has multiple solutions.\n";
        }
        else
            cout<<"Case not valid.\n";
    }

    return 0;
}

posted on 2011-03-11 20:42  acmaru  阅读(178)  评论(0编辑  收藏  举报

导航