zoukankan      html  css  js  c++  java
  • N个投机取巧的数独棋盘

    1,代码:

    1.1主函数 

    #include "stdafx.h"

    #include <stdlib.h>

    #include "iostream"

    #include "ChessBoard.h"

    #include "fstream"

    #include "sstream"

    using namespace std;

     

    int main(int argc, char* argv[])

    {

        ChessBoard CB;

        int bn = 0;//board number

        string s = argv[2];

        stringstream ss;

        ss << s;

        ss >> bn;

        ofstream file("sudotiku.txt");

        for (int i = 0; i < bn; i++){

            CB.printChessBoard(file);

            CB.exchange();  

            file << endl;

            cout << endl;

        }

        file.close();

        cout << "执行完毕,请检查";

        system("pause");

        return 0;

    }

    1.2类头文件

    #pragma once

    #include "fstream"

    using namespace std;

    class ChessBoard

    {

    public:

        ChessBoard();

        ~ChessBoard();

        int*  getExchangedNum();

        ofstream& printChessBoard(ofstream &);

        void exchange();

    private:

        int exchangedNum[9];//已经交换过的数

        int enumNum[9];

        int chessBoardRelationship[9][9];

    };

    1.3类

    #include "stdafx.h"

    #include "ChessBoard.h"

    #include "iostream"

    #include <stdlib.h>

    #include<windows.h>

    #include "fstream"

    using namespace std;

    ChessBoard::ChessBoard()

    {

        int init[9][9] ={

                { 1, 2, 3, 5, 6, 7, 9, 4, 8 },

                { 4, 5, 6, 8, 9, 1, 3, 7, 2 },

                { 7, 8, 9, 2, 3, 4, 6, 1, 5 },

                { 9, 4, 8, 1, 2, 3, 5, 6, 7 },

                { 3, 7, 2, 4, 5, 6, 8, 9, 1 },

                { 6, 1, 5, 7, 8, 9, 2, 3, 4 },

                { 5, 6, 7, 9, 4, 8, 1, 2, 3 },

                { 8, 9, 1, 3, 7, 2, 4, 5, 6 },

                { 2, 3, 4, 6, 1, 5, 7, 8, 9 }

        };

        for (int i = 0; i < 9; i++){

            for (int j = 0; j < 9; j++){

                chessBoardRelationship[i][j]=init[i][j];  

            }

        }

        exchange();

    }

    void ChessBoard::exchange(){

        for (int i = 0; i < 9; i++){

            enumNum[i] = i + 1;

        }

        int p = 0;

        for (int i = 0; i < 9; i++){

     

            LARGE_INTEGER nFrequency;

            if (::QueryPerformanceFrequency(&nFrequency))

            {

                LARGE_INTEGER nStartCounter;

                ::QueryPerformanceCounter(&nStartCounter);

                ::srand((unsigned)nStartCounter.LowPart);

            }

     

            p = rand() % (9 - i);

            exchangedNum[i] = enumNum[p];

            enumNum[p] = enumNum[8 - i];

        }

    }

    ChessBoard::~ChessBoard()

    {

    }

    int* ChessBoard::getExchangedNum(){

        return &(exchangedNum[0]);

    }

    ofstream & ChessBoard::printChessBoard(ofstream &file){

        int count=0;

        int count1=0;

        for (int i = 0; i < 9; i++){

            for (int j = 0; j < 9; j++){

                cout << exchangedNum[chessBoardRelationship[i][j]-1]<<" ";

                file << exchangedNum[chessBoardRelationship[i][j] - 1] << " ";

                count++;

                if (count % 3 == 0){

                    cout << "   ";

                    file << "   ";

                }

            }

            count1++;

            if (count1 % 3 == 0){

                cout << endl;

                file << endl;

            }

            cout << endl;

            file << endl;

        }

        return file;

    }

    2,分析:

      以上代码几乎没有注释,这没有关系,本人也从来没有玩过数独游戏,这也没关系,让我们从最原始的问题开始。

      首先,一个数独棋盘应是有解的,在提示数足够多的情况下,它应是有唯一解的。我曾注意到一位同僚,在随机生成n个数独棋盘这个问题上,采取如下策略:先求解出一个棋盘,然后,随机重新排列每个三行、每个三列、每三个三行和每三个三列。这样做显然不会违背数独规则,但是,其中似乎有些不变的东西。

      从线性代数的角度看,这显然是一个无法再化简的矩阵,也就是说,无论怎样变化,它还是同一个矩阵,那么,我们可以很容易地手写一个矩阵,假定它最终可以变换为这样的关系形式:

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

      请注意,这只是一种关系形式,而不是最终输出的数值,其中每两个数之间没有任何关系,这个矩阵嘛就是代码中给出的chessBoardRelationship矩阵。

      这个矩阵明显是死的,那么我们应当对它进行变换,按照上面的描述,策略如下:1对应的数值是在1到9之中随机的,而且一旦确定,则这个对应的映射关系不能被其它映射所破坏,即数值不能被重复选定。我们使用两个数组来描述这样的映射关系。

      最终问题,输出,按照关系数组的格式,根据关系数组的数值查找映射,输出数值,由于此时关系数组每个数值对应的映射时随机的,可能出现的映射总量为9位数,问题得到解决。

      这其中涉及到一些细节,比如,如何让映射关系不重复,如何在运行函数时传入参数,内联函数等,这些在网络上都能得到详尽的解答,再次不再赘述。

      关于程序运行的效率,需要在此代码的基础上屏蔽到控制台的输出,然后测试,经测试,实际在形成10000个数独棋盘时,命令行下光标闪烁5次,由于在本机上光标每秒闪烁一次,估算的运行效率为,5秒以内,形成10000个已经解答的数独棋盘并输出到文件。经使用visual studio自带测试工具,总cpu时间稳定在4700毫秒。(测试平台:ThinkPad E485 AMD_Ryzen5 2500U 8G)

    3,心得

      3.1,写程序要善于“投机取巧”,

      3.2,要善于思考已有的方案。

      最开始拿到这个题目时,我曾花费大量精力,连续四天,力图使其在每一个位置上随机输出正确的数字,并力图一次形成未解答的棋盘和答案,甚至离成功只有一步之遥,然而,在了解他人的做法以后,迅速跳出了这个圈子,即便是想达到题目之外的要求,也可以先得出已解答的棋盘,再从中选取提示数,从构思直到最终确认实现题目要求,在几乎没有c++基础的情况下,6小时就达成要求。

  • 相关阅读:
    Displaying XML in a Swing JTree
    jdom解析xml
    How to display XML in a JTree using JDOM
    关于XML文档和JAVA中的JTree之间如何转换的问题
    java swing 学习
    硅谷创业教父Paul Graham:如何获得创业idea
    如何成为一位优秀的创业CEO
    硅谷归来7点分享:创业者,做你自己
    The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 C Buy Watermelon
    The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 B so easy
  • 原文地址:https://www.cnblogs.com/XieJingcheng/p/9742069.html
Copyright © 2011-2022 走看看