回溯法解数独

#include <stdafx.h>
#include<stdio.h>  
#include <cstdlib>
int g_nCount=0;
void print(int array[9][9])//输出可行的解  
{  
    printf("第%d个解:\n",++g_nCount);
    for(int i=0;i<9;i++)  
    {  
        for(int j=0;j<9;j++)  
        {  
            printf("%d ",array[i][j]);  
            if((j==2)||(j==5))  
                printf(" ");  
        }  
        printf("\n");  
        if((i==2)||(i==5))  
            printf("\n");  
    }   
    printf("\n----------------------------------\n");  
}  

//寻找前一个可填数的位置,找到后修改nRow和nCol的值。
bool PreFillPos(int QuestionArray[9][9],int &nRow,int &nCol)
{
    int *pLineArray=(int *)QuestionArray;//二维数组变为一维的
    for (int i=nRow*9+nCol-1;i>=0;i--)
    {
        if(pLineArray[i]==0)
        {
            nRow=i/9;
            nCol=i%9;
            return true;
        }
    }
    return false;
}
//寻找下一个可填数的位置,找到后修改nRow和nCol的值。
bool NextFillPos(int QuestionArray[9][9],int &nRow,int &nCol)
{
    int *pLineArray=(int *)QuestionArray;
    for (int i=nRow*9+nCol+1;i<81;i++)
    {
        if(pLineArray[i]==0)
        {
            nRow=i/9;
            nCol=i%9;
            return true;
        }
    }

    return false;
}

//检测AnswerArray中nRow,nCol中的数在行方向是否合法
bool CheckRow(int AnswerArray[9][9],const int nRow,const int nCol)
{
    for (int j=0;j<9;j++)
    {
        if((AnswerArray[nRow][j]==AnswerArray[nRow][nCol])&&(j!=nCol))
        {
            return false;
        }
    }
    return true;
}
//检测AnswerArray中nRow,nCol中的数在列方向是否合法
bool CheckCol(int AnswerArray[9][9],const int nRow,const int nCol)
{
    for (int i=0;i<9;i++)
    {
        if((AnswerArray[i][nCol]==AnswerArray[nRow][nCol])&&(i!=nRow))
        {
            return false;
        }
    }
    return true;
}
//检测AnswerArray中nRow,nCol中的数在所属的九宫格中是否合法
bool CheckArea(int AnswerArray[9][9],const int nRow,const int nCol)
{
    int nBeginRow=(nRow/3)*3;
    int nBeginCol=(nCol/3)*3;
    for (int i=0;i<3;i++)
    {
        for (int j=0;j<3;j++)
        {
            if (AnswerArray[nBeginRow+i][nBeginCol+j]==AnswerArray[nRow][nCol]\
                &&nBeginRow+i!=nRow\
                &&nBeginCol+j!=nCol)
            {
                return false;
            }
        }
    }

    return true;
}
//检测AnswerArray中nRow,nCol中的数在数独中是否合法
bool CheckShudu(int AnswerArray[9][9],const int nRow,const int nCol)
{
    return CheckRow(AnswerArray,nRow,nCol)&&CheckCol(AnswerArray,nRow,nCol)&&CheckArea(AnswerArray,nRow,nCol);
}
//解数独,QuestionArray为原数独,主要起参考作用,不可改变。AnswerArray为解答的数组,它保存当前的解答进度。nRow, nCol表示运算到AnswerArray的位置
void JieShudu(int QuestionArray[9][9],int AnswerArray[9][9],int nRow,int nCol)
{
    if (!NextFillPos(QuestionArray,nRow,nCol))
    {//说明找到,输出来
        print(AnswerArray);
    }
    else
    {
        for (int i=1;i<=9;i++)
        {
            AnswerArray[nRow][nCol]=i;
            if (CheckShudu(AnswerArray,nRow,nCol))
            {
                JieShudu(QuestionArray,AnswerArray,nRow,nCol);
            }
        }
        AnswerArray[nRow][nCol]=0;//恢复到最初
    }
}
//第一种解法
void Shudu1(int QuestionArray[9][9])
{
    int anser[9][9]={0};
    memcpy(anser,QuestionArray,sizeof(int[9][9]));
    JieShudu(QuestionArray,anser,0,-1);
}

bool FillRightNumber(int AnserArray[9][9],const int nRow,const int nCol)
{
    while (true)
    {
        AnserArray[nRow][nCol]++;
        if (AnserArray[nRow][nCol]>9)
           return false;
        if (CheckShudu(AnserArray,nRow,nCol))
           return true;
    }
}

bool BackPreRightPos(int QuestionArray[9][9],int AnserArray[9][9],int &nRow,int &nCol)
{   
    AnserArray[nRow][nCol]=0;//向前找前先把当前位置恢复0
    bool bRet=PreFillPos(QuestionArray,nRow,nCol);
    if (bRet)
    {
        if (!FillRightNumber(AnserArray,nRow,nCol))
        {
            return BackPreRightPos(QuestionArray,AnserArray,nRow,nCol);
        }
    
    }
    return bRet;
}
//第二种解法
void Shudu2(int QuestionArray[9][9])
{
    int anser[9][9]={0};
    memcpy(anser,QuestionArray,sizeof(int[9][9]));
    int nRow=0;
    int nCol=-1;

    while(true)
    {
        if (NextFillPos(QuestionArray,nRow,nCol))
        {
            if (!FillRightNumber(anser,nRow,nCol))
            {//没有合适的数填充就回溯到前一个正确的可填充的位置继续向后找
                if(!BackPreRightPos(QuestionArray,anser,nRow,nCol))
                    return ;
            }
        }
        else
        {
            print(anser);
            //寻找下一组答案
            if(!BackPreRightPos(QuestionArray,anser,nRow,nCol))
                return;
        }
    }
}

int main()  
{  
    int a[9][9]=
    {
        /*{0, 0, 0, 0, 0, 0, 0, 1, 2},  
        {0, 0, 0, 0, 3, 5, 0, 0, 0},  
        {0, 0, 0, 6, 0, 0, 0, 7, 0},  
        {7, 0, 0, 0, 0, 0, 3, 0, 0},  
        {0, 0, 0, 4, 0, 0, 8, 0, 0},  
        {1, 0, 0, 0, 0, 0, 0, 0, 0},  
        {0, 0, 0, 1, 2, 0, 0, 0, 0},  
        {0, 8, 0, 0, 0, 0, 0, 4, 0},  
        {0, 5, 0, 0, 0, 0, 6, 0, 0}  */

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

    };  
    
    Shudu1(a);
    g_nCount=0;
    Shudu2(a);
    system("pause");
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值