蓝桥杯——数独(DFS详解)

题目(填空)

在这里插入图片描述

思路

拿到题首先想到的是人做?不可能的太玄学了,除非你真的很会数独。

那就暴力——搜索吧,也就是满足一个数就填进格子里去,然后进入下一层,不满足的话就退回来,把填进去的数取掉。

当然其中最主要的就是符合数独的规则:
1、同行无相同数字;
2、同列无相同数字;
3、9个3*3九宫格内无相同数字。

那么如何满足这三个规则呢?一共九个数 1~9。

1、针对第一个规则,建立布尔类型二维数组 row[10][10] 进行行标记(初始全为0)
如: row[5][6]=1 就代表第5行填入数字,且为6

2、针对第二个规则,建立布尔类型二维数组 col[10][10] 进行列标记(初始全为0)
如: col[5][6]=1 就代表第5列填入数字,且为6

3、针对第三个规则,建立布尔类型三维数组 mat[3][3][10] 进行3*3九宫格标记(初始全为0),为何前两个数字为3 ?因为9行9列如果以9宫格为行列的话就是3行3列
如: mat[0][0][5]=1 就代表第1行第1列九宫格填入数字,且为5

最后我们只需让计算机暴力跑图,只要这三个数组中有为0的就说明有数字没填入网格。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define M 10
using namespace std;
struct point  //存未填空的行列坐标
{
    int x, y;
} p[100];
int flag;
bool row[M][M];  //行标记
bool col[M][M];   //列标记
bool mat[3][3][M];   //九宫格标记
int np = 0;   //记录图中没填入数字的个数
int Map[M][M]= {
{0,2,6,0,0,0,0,0,0},
{0,0,0,5,0,2,0,0,4},
{0,0,0,1,0,0,0,0,7},
{0,3,0,0,2,0,1,8,0},
{0,0,0,3,0,9,0,0,0},
{0,5,4,0,1,0,0,7,0},
{5,0,0,0,0,1,0,0,0},
{6,0,0,9,0,7,0,0,0},
{0,0,0,0,0,0,7,5,0}};   //要跑的图
void dfs(int n)
{
    if(flag)    //flag==1,图已填满
        return ;
    if(n==-1&&flag==0)    
    //每次进入dfs,未填空数n要减1,p[0]中也有记录为填空的行列坐标,则最后一次进入dfs时n==-1
    //当n==-1时,说明图已经填完,flag==0,说明还未输出
    {
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<8;j++)
            {
                printf("%d ",Map[i][j]);
            }
            printf("%d\n",Map[i][8]);
        }
        flag=1;   //已经输出,且图满
    }
    for(int i=1;i<=9&&flag==0;i++)    //i为要填写的数字的可能性1~9
    {
        int x=p[n].x;   //第x行
        int y=p[n].y;   //第y列
        if(!row[x][i]&&!col[y][i]&&!mat[x/3][y/3][i])  //三个约束条件
        {
            row[x][i]=col[y][i]=mat[x/3][y/3][i]=1;  //满足至1
            Map[x][y]=i;  //填入该数字
            dfs(n-1);   //进入下一个空
            row[x][i]=col[y][i]=mat[x/3][y/3][i]=0;   //不满足恢复标记0
            Map[x][y]=0;   //取出该数字
        }
    }
}
int main()
{
    flag=0;   //图中若有没填写的数字为0,填满为1
    memset(row,0,sizeof(row));
    memset(col,0,sizeof(col));
    memset(mat,0,sizeof(mat));
     for(int i=0;i<9;i++)
    {
        for(int j=0;j<9;j++)
        {
            int num=Map[i][j];
            if(num)   //若数字不为0,则说明该空已填写数字
            {
                row[i][num]=col[j][num]=mat[i/3][j/3][num]=1;   
                //则该行该列该九宫格至1
            }
             else      //若该数字为0,则说明该空没有填写数字
            {
                p[np].x=i;
                p[np++].y=j;

                //记录该空的行列坐标
            }
        }
    }
    dfs(np-1);    //np-1为未填写数字的空数,之前np++了哦
    return 0;
 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值