另一個數獨求解c++程式

lt發表於2016-09-28

來自這裡,他用多種語言實現了同一種方法。包括c++、python、cs等。

#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;

typedef int coord;
typedef int block;

enum view { GRD, ROW, COL, BOX };

const int VIEW    = 4;
const int UNIT    = 3;
const int SIZE    = UNIT * UNIT;
const int COORD   = SIZE * SIZE * SIZE;
const int BLOCK   = VIEW * SIZE * SIZE;
const int DEFINED = 0xDEF;

const string DIGITS = "123456789";

inline coord coord_of(int i, int j, int k) {
    return (i * SIZE + j) * SIZE + k;
}

inline block block_of(view v, int p, int q) {
    return (v * SIZE + p) * SIZE + q;
}

vector<block> parents[COORD];
vector<coord> children[BLOCK];

void init() {
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            int p = i / UNIT * UNIT + j / UNIT;
            for (int k = 0; k < SIZE; k++) {
                coord c = coord_of(i, j, k);
                parents[c].push_back(block_of(GRD, i, j));
                parents[c].push_back(block_of(ROW, i, k));
                parents[c].push_back(block_of(COL, j, k));
                parents[c].push_back(block_of(BOX, p, k));
            }
        }
    }
    for (coord c = 0; c < COORD; c++)
        for (block b : parents[c])
            children[b].push_back(c);
}

class no_solution_exception {} NO_SOLUTION_EXCEPTION;

class sudoku {

    public:

        static string solve(string input) {
            try {
                sudoku s;
                return s.read(input).search().to_string();
            }
            catch (no_solution_exception) {
                return "NO SOLUTION";
            }
        }

    private:

        bool admit[COORD];

        int count[BLOCK];

        sudoku() {
            for (coord c = 0; c < COORD; c++)
                admit[c] = true;
            for (block b = 0; b < BLOCK; b++)
                count[b] = SIZE;
        }

        sudoku(const sudoku& s) {
            for (coord c = 0; c < COORD; c++)
                admit[c] = s.admit[c];
            for (block b = 0; b < BLOCK; b++)
                count[b] = s.count[b];
        }

        sudoku& search() {

            int min = DEFINED;
            int bmin = -1;
            for (block b = 0; b < BLOCK; b++) {
                if (count[b] < min) {
                    min = count[b];
                    bmin = b;
                }
            }

            if (min == DEFINED)
                return *this;

            for (coord c : children[bmin]) {
                if (admit[c]) {
                    try {
                        sudoku s(*this);
                        return s.assign(c).search();
                    }
                    catch (no_solution_exception) {
                    }
                }
            }

            throw NO_SOLUTION_EXCEPTION;
        }

        sudoku& read(string input) {
            int l = min(int(input.length()), SIZE * SIZE);
            for (int ij = 0; ij < l; ij++) {
                int k = DIGITS.find(input[ij]);
                if (k != -1)
                    assign(coord_of(ij / SIZE, ij % SIZE, k));
            }
            return *this;
        }


        sudoku& assign(coord c) {
            queue<coord> queue;
            queue.push(c);
            while (! queue.empty()) {
                int c0 = queue.front();
                queue.pop();
                if (! admit[c0])
                    throw NO_SOLUTION_EXCEPTION;
                for (block b1 : parents[c0]) {
                    count[b1] = DEFINED;
                    for (coord c2 : children[b1]) if (c2 != c0 && admit[c2]) {
                        admit[c2] = false;
                        for (block b3 : parents[c2]) if (b3 != b1) {
                            count[b3]--;
                            if (count[b3] == 0)
                                throw NO_SOLUTION_EXCEPTION;
                            if (count[b3] == 1)
                                for (coord c4 : children[b3]) if (admit[c4])
                                    queue.push(c4);
                        }
                    }
                }
            }
            return *this;
        }

        string to_string() {
            string output;
            for (int i = 0; i < SIZE; i++) {
                for (int j = 0; j < SIZE; j++) {
                    vector<int> ks;
                    for (int k = 0; k < SIZE; k++)
                        if (admit[coord_of(i, j, k)])
                            ks.push_back(k);
                    if (ks.size() == 1)
                        output += DIGITS[ks[0]];
                    else
                        output += '.';
                }
            }
            return output;
        }
};

int main() {
    init();
    string input;
    while (cin >> input)
        cout << sudoku::solve(input) << endl;
    return 0;
}

原始碼中用到了部分c++ 2011標準的功能,但vc 2015沒有實現,比如and和not關鍵字。把它們改為 &&和!後,編譯通過,在連結時,預設需要和windows sdk中的uuid.lib連結,改用/MD選項,與kernel32.lib連結通過。

D:\>cl sudoku.cpp /EHsc /MD /O2 /link D:\VS2010SP1\WINSDK_v7.0A\Lib\kernel32.lib
用於 x86 的 Microsoft (R) C/C++ 優化編譯器 19.00.23026 版
版權所有(C) Microsoft Corporation。保留所有權利。

sudoku.cpp
Microsoft (R) Incremental Linker Version 14.00.23026.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:sudoku.exe
D:\VS2010SP1\WINSDK_v7.0A\Lib\kernel32.lib
sudoku.obj

D:\>a\timer sudoku <sudoku17.16000.txt >sudoku17.16000_vc15.txt

Timer 3.01  Copyright (c) 2002-2003 Igor Pavlov  2003-07-10

Kernel Time  =     0.156 = 00:00:00.156 =   9%
User Time    =     0.998 = 00:00:00.998 =  60%
Process Time =     1.154 = 00:00:01.154 =  70%
Global Time  =     1.638 = 00:00:01.638 = 100%

最終時間是1.6秒,同樣的機器上,pypy執行python版本是3.76秒,csc編譯cs後執行是3.9秒。命令列引數分別是

\timer pypy d:\sudoku.py d:\sudoku17.16000.txt >d:\sudoku17_16000py.txt 
\timer sudoku <d:\sudoku17.16000.txt >d:\sudoku17_16000cs.txt

說明:他的cs版本也用到了新功能,除了安裝.net framwork 4.62外,還要更新c#編譯器。 nuget工具是從csc提示的連線處下載的。

D:\>c:csc sudoku.cs
Microsoft (R) Visual C# Compiler version 4.6.1590.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240

D:\>nuget install Microsoft.Net.Compilers

D:\>Microsoft.Net.Compilers.1.3.2\tools\csc sudoku.cs
Microsoft (R) Visual C# Compiler version 1.3.1.60621
Copyright (C) Microsoft Corporation. All rights reserved.

相關文章