zoukankan      html  css  js  c++  java
  • c++实现的简单数独计算器

    平时挺喜欢写小程序的,但是不知道写啥,偶然看到关于数独的新闻,觉得用小程序实现再合适不过了,网上一搜,有原理,有程序,但是没有找到优秀的代码,干脆自己写了一个,虽然也不优秀,起码自己看得懂。

    原理:

    1、每个格子可以是1-9的数,n行m列的数确定后,则第n行,第m列,nm所在的”宫“里其他的格子就不能是这个数了。

    2、刚开始每个格子都有9个”候选数“,逐步把初始数据添加到最终的格子中,并把相应的格子中的候选数更新,如1所说。

    3、开始计算,选出候选数最少的格子,对这些数迭代测试,如把候选数中的第1个添加到最终的格子中。和2一样更新其他格子的候选数列表。

    4、3之后自然还是3,所以把3实现为递归要简单一些。而且考虑到本题实际情况最多递归81层,不会栈溢出。而且递归本身还保存了后续所需数据,简化了操作。

    代码注释:

    g_currentIndex:格子中已经确定结果的个数(添加到格子中的数的个数,递归的深度),索引表示的,所以0代表已添加1个。

    g_affectedFlags:位标志,某次添加数据是否对格子产生影响,回退操作要使用。

    g_candidate:每个格子的候选列表,用bitset的索引表示。第n位为1,代表n是候选数。

    g_candidateNum:每个格子的候选个数,为什么不用bitset的count呢?因为速度太慢。

    结果截图:

    源码:

    #include<iostream>
    #include<set>
    #include<bitset>
    #include<cstring>
    #include<time.h>
    
    using namespace std;
    
    int g_currentIndex=-1;
    bitset<81> g_affectedFlags[9][9];
    bitset<10> g_candidate[9][9];
    int g_candidateNum[9][9];
    int resultNum;
    const int maxNum=5;
    
    int g_map[9][9]={
    {8,0,0,0,0,0,0,0,0},
    {0,0,3,6,0,0,0,0,0},
    {0,7,0,0,9,0,2,0,0},
    {0,5,0,0,0,7,0,0,0},
    {0,0,0,0,4,5,7,0,0},
    {0,0,0,1,0,0,0,3,0},
    {0,0,1,0,0,0,0,6,8},
    {0,0,8,5,0,0,0,1,0},
    {0,9,0,0,0,0,4,0,0},
    };
    
    void AddElement(int row,int column,int num)
    {
        ++g_currentIndex;
        g_map[row][column]=num;
        
        int old;
        for(int i=0;i<9;++i)
        {
            if(g_map[row][i]==0 && g_candidate[row][i].test(num))
            {
                g_candidate[row][i].reset(num);
                --g_candidateNum[row][i];
                g_affectedFlags[row][i].set(g_currentIndex);
            }
                
            if(g_map[i][column]==0 && g_candidate[i][column].test(num))
            {
                g_candidate[i][column].reset(num);
                --g_candidateNum[i][column];
                g_affectedFlags[i][column].set(g_currentIndex);
            }
        }
        
        int palaceRow=row>2?(row>5?6:3):0;
        int palaceColumn=column>2?(column>5?6:3):0;
        
        for(int i=0;i<3;++i)
        {
            for(int j=0;j<3;++j)
            {
                row=palaceRow+i;
                column=palaceColumn+j;
                if(g_map[row][column]==0 && g_candidate[row][column].test(num))
                {
                g_candidate[row][column].reset(num);
                --g_candidateNum[row][column];
                g_affectedFlags[row][column].set(g_currentIndex);
                }
            }
        }
    }
    
    void RecoverElement(int row,int column,int num)
    {
        g_map[row][column]=0;
        for(int i=0;i<9;++i)
        {
            if(g_map[row][i]==0 && g_affectedFlags[row][i].test(g_currentIndex))
            {
                g_candidate[row][i].set(num);
                ++g_candidateNum[row][i];
                g_affectedFlags[row][i].reset(g_currentIndex);
            }
            
            if(g_map[i][column]==0 && g_affectedFlags[i][column].test(g_currentIndex))
            {
                g_candidate[i][column].set(num);
                ++g_candidateNum[i][column];
                g_affectedFlags[i][column].reset(g_currentIndex);
            }            
        }
        
        int palaceRow=row>2?(row>5?6:3):0;
        int palaceColumn=column>2?(column>5?6:3):0;
        
        for(int i=0;i<3;++i)
        {
            for(int j=0;j<3;++j)
            {
                row=palaceRow+i;
                column=palaceColumn+j;
                if(g_map[row][column]==0 && g_affectedFlags[row][column].test(g_currentIndex))
                {
                g_candidate[row][column].set(num);
                ++g_candidateNum[row][column];
                g_affectedFlags[row][column].reset(g_currentIndex);
                }    
            }
        }
            
        --g_currentIndex;    
    }
    
    void Init()
    {
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                g_candidate[i][j].set();
                g_candidateNum[i][j]=10;
            }
        }
    
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                if(g_map[i][j]!=0)
                    AddElement(i,j,g_map[i][j]);
            }
        }
    }
    
    bool FindBest(int &row,int &column)
    {
        int min=999;
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                if(g_map[i][j]==0 && g_candidateNum[i][j]>1 && g_candidateNum[i][j]<min)
                {
                    row=i;
                    column=j;
                    min=g_candidateNum[i][j];
                }            
            }
        }
        
        if(min==999)
            return false;
        return true;
    }
    
    bool CheckResult()
    {
        set<int> elements;
        set<int> elements2;
        
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                elements.insert(g_map[i][j]);
                elements2.insert(g_map[j][i]);
            }
            if(elements.size()!=9)
                return false;
            if(elements2.size()!=9)
                return false;
            elements.clear();
            elements2.clear();
        }
        
        elements.clear();
        int row,column;
        for(int i=0;i<3;++i)
        {
            for(int j=0;j<3;++j)
            {
                row=i*3;
                column=j*3;
                for(int k=0;k<9;++k)
                {
                    elements.insert(g_map[row+k/3][column+k%3]);
                }
                if(elements.size()!=9)
                    return false;
                    
                elements.clear();
            }
        }
        return true;    
    }
    
    void OutputResult()
    {
        cout<<endl;
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                cout<<g_map[i][j]<<" ";
            }
            cout<<endl;
        }
    }
    
    bool Try()
    {
        int row,column;
        if(!FindBest(row,column))
            return true;
    
        for(int i=1;i<10;++i)
        {
            if(!g_candidate[row][column].test(i))
                continue;
        
            AddElement(row,column,i);
            
            if(Try())
            {
                if(g_currentIndex==80 && CheckResult())
                {
                    cout<<endl<<"Result:"<<++resultNum<<endl;
                    OutputResult();
                    
                    if(resultNum>=maxNum)
                        return false;
                
                }
            }
            else
                return false;
            
            RecoverElement(row,column,i);    
        }
        
        return true;
    }
    
    int main()
    {    
        double start,end,cost;
        start=clock();
        
        Init();
        Try();
        
        if(resultNum)
            cout<<endl<<"OK!"<<endl;
        else
            cout<<endl<<"Wrong Input!"<<endl;
        
        end=clock();
        cost=end-start;
        cout<<"Costed time:"<<cost<<"ms"<<endl;
        
        char c;
        cin>>c;
        
        return 0;
    }

    其他:

    个人觉得这种方法已经到了速度的极限,高手的代码竟然能够达到几十毫秒,表示自叹不如!

    我用的例子是”史上最难数独“,确实只有一个解,代码中maxNum可以限制显示结果数量。

    附其他高手的截图一张:

  • 相关阅读:
    x264参数
    用X264编码以后的H264数据
    (转)YUV420存储格式
    YUV数据YUY2到I420
    udp编程中,一次能发送多少个bytes为好?
    (转)c++多态实现的机制
    linux下ping加时间戳实时输出到文件 放后台运行
    如何向AcmeAir注入问题代码
    AcmeAir
    Jmeter压力测试
  • 原文地址:https://www.cnblogs.com/qq499194341/p/3107659.html
Copyright © 2011-2022 走看看