cqyz#p1194 数独

【问题描述】  

  数独是一个风靡全球的解谜游戏。它的规则如下:
  在一个9*9的方格中,有一些位置上已经填有数字。你需要把1~9填写到空格当中,并且使用方格的每一行,每一列中包含1~9这九个数字。同时还要保证,空格中用粗线划分的9个3*3的方格也同时包含1~9这九个数字。下图是一个数独的样例:
        

  现在给出一个数独,请你找出他的解。

【输入格式】

  输入数据一共9行,每行有9个字符。
  输入数据描述了一个待解决的数独,其中,“?”表示数独中的空缺。
  我们的输入数据总保证有唯一解。

【输出格式】

  输出一共9行,每行9个数字,表示你的答案。

【输入样例】

5????7??6
?6????5?4
?834?????
???182?4?
??1???9??
?7?369???
?????543?
1?5????9?
7??2????1

【输出样例】

514927386
967831524
283456179
659182743
321574968
478369215
892615437
135748692
746293851

【数据范围】

  输入的数据保证答案唯一。
  


【问题分析】
一道很经典的回溯题,如果采用枚举铁定超时,因此采用回溯法解决此类向表中填数字判断是否合法的问题。
1.分步:共9行9列(x,y)
2.每步:每一个格子都有1~9个选项,弹药注意约束
3.约束:每行每列每个九宫格不许相同
4.选择后若此行未填完,则填下一列;否则填下一行第一列
5.求解:当填完最后一个格子后即可输出

【细节分析】
1.约束条件的写法
定义三个bool函数
bool ok=0,ge[4][4][10],h[10][10],l[10][10];
ge表示九个小九宫格的情况,h表示每一行的情况,l表示每一列的情况
tip:小九宫格的大坐标为(x/3,y/3)
2.预处理
每一行采用字符串输入
输入后应将已经填的的数放入要填的表中
且将其标记为true
3.每次找到合法的数字进入下一层后,除了要解除三个标记数组的标记,还需将已经填入表的数字擦除(因为这也是判断是否填数的条件!!
4.由题意,因为所给数据只有一个解,所以可以定义一个ok=0,只要找到了一组解后ok=1;
只要当ok=1后即可跳出递归——>避免不必要的重复~~~


#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
bool ok=0,ge[4][4][10],h[10][10],l[10][10];//ge表示九个小九宫格的情况,h表示每一行的情况,l表示每一列的情况 
int map[11][10];
char ch[10]; 
void input_()
{
    for(int i=0;i<9;i++)
    {
        scanf("%s",ch);
        for(int j=0;j<9;j++)
        if(ch[j]!='?')
        {
            map[i][j]=ch[j]-'0';
            ge[i/3][j/3][map[i][j]]=l[j][map[i][j]]=h[i][map[i][j]]=1;
        }
    }
}

void output_()
{
    for(int i=0;i<9;i++)
    {
    for(int j=0;j<9;j++)
    printf("%d",map[i][j]); 
    printf("\n");
    }
}

bool judge(int i,int x,int y)
{
    if(ge[x/3][y/3][i]==0&&
       l[y][i]==0&&
       h[x][i]==0)return 1;
    return 0;
}

void run(int x,int y)//x表示行y表示列 
{
    if(x==9)
    {
        output_();
        ok=1;
        return;
    }

    if(map[x][y]!=-1)
    {
        if(y==8)run(x+1,0);
        else run(x,y+1);
        return;
    }
    for(int i=1;i<=9;i++)if(judge(i,x,y)==1)//if(h[x][i]==false && l[y][i]==false && ge[x/3][y/3][i]==false)////每一行枚举1~9 
    {
        map[x][y]=i;
        ge[x/3][y/3][i]=l[y][i]=h[x][i]=1;
        if(y==8)run(x+1,0);
        else run(x,y+1);
        if(ok)return;//避免多余的分枝 
        ge[x/3][y/3][i]=l[y][i]=h[x][i]=0;
        map[x][y]=-1;//需将已填的数字也擦除!! 

    }

}
int main()
{
     //freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
     memset(map,-1,sizeof(map));
     input_();
     run(0,0);
     return 0;
}



Written by Mr.Shadow from CQYZ

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值