C - DFS 数独

数独是一个非常简单的任务。一个9行9列的方桌被分割成9个较小的3 * 3的正方形,如图所示。有些单元格写的是从1到9的十进制数字。其他单元格是空的。目标是用从1到9的十进制数字填充空单元格,每个单元格一个数字,这样在每一行、每一列和每一个标记为3x3的子正方形中,从1到9的所有数字都会出现。编写一个程序来解决给定的数独任务。
在这里插入图片描述

Input
输入数据将从测试用例的数量开始。对于每个测试用例,后面有9行,对应于表中的行。每一行都给出了与这一行的单元格对应的9位小数。如果单元格为空,则用0表示。
Output
对于每个测试用例,您的程序应该以与输入数据相同的格式打印解决方案。空单元格必须根据规则进行填充。如果解决方案不是唯一的,那么程序可以打印其中的任何一个。
Sample Input
1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107

Sample Output
143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127

思路是:
矩阵最多是9*9,所以可以用dfs直接搜。

int n;
char mp[10][10];
int ans[10][10];//答案矩阵
bool v[4][10][10],fl=0;
//v[0][i][j]表示第i个矩阵中j是否出现
//v[1][i][j]表示第i行中j是否出现
//v[2][i][j]表示第i列中j是否出现
//v[3][i][j]表示第mp[i][j]是否访问

然后需要一个函数来判断在第几个矩阵,我们依次将矩阵编号为1~9。

int joing(int x,int y)
{
    if(x<=3){
        if(y<=3) return 1;
        if(y>3&&y<=6) return 2;
        if(y>6&&y<=9) return 3;
    }
    if(x>3&&x<=6){
        if(y<=3) return 4;
        if(y>3&&y<=6) return 5;
        if(y>6&&y<=9) return 6;
    }
    if(x>6&&x<=9){
        if(y<=3) return 7;
        if(y>3&&y<=6) return 8;
        if(y>6&&y<=9) return 9;
    }
}

因为有多组数据,所以特别注意要清零。然后输入mp[][],如果不为0,那么ans[][]中就可以直接填入,否则就把当前位置保留为0。紧接着就一个dfs。

	cin>>n;
    while(n--)
    {
        memset(ans,0,sizeof(ans));
        memset(v,0,sizeof(v));
        fl=0;//判断是否已经找到
        //千万注意
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
            {
                cin>>mp[i][j];
                if(mp[i][j]!='0'){
                    ans[i][j]=mp[i][j]-'0';
                    v[0][joing(i,j)][ans[i][j]]=1;
                    v[1][i][ans[i][j]]=1;
                    v[2][j][ans[i][j]]=1;
                }
            }
        }
        dfs(1,1);
        //从[1][1]开始
    }
    //主函数部分

接下来就是重磅推出的dfs了。
其实里面有些多余的代码······
每个格子循环1~9判断可不可以填,如果可以就dfs,如果找不到就回溯。
判断条件:
同一行、同一列、同一矩阵不含i,则可以填。

void dfs(int x,int y)
{
    if(fl) return;//找到就不用搜了
    if(x==9&&y==9)
    {//到达终点
        print();
        fl=1;
        return;
    }
    if(ans[x][y]==0)//如果该位置未填,则可以尝试
    for(int i=1;i<=9;i++)
    {
        if(!v[0][joing(x,y)][i]&&!v[1][x][i]&&!v[2][y][i]&&!v[3][x][y])
        {//判断条件
            v[0][joing(x,y)][i]=1;
            v[1][x][i]=1;
            v[2][y][i]=1;
            v[3][x][y]=1;
            ans[x][y]=i;
            if(y<9) dfs(x,y+1);
            else dfs(x+1,1);//这里是每行每个依次搜,如果到行末就换行搜
            ans[x][y]=0;
            v[0][joing(x,y)][i]=0;
            v[1][x][i]=0;
            v[2][y][i]=0;
            v[3][x][y]=0;//回溯
        }
    }
    else{
        if(y<9) dfs(x,y+1);
        else dfs(x+1,1);//如果已填,就直接搜下一个
    }
}

最后的最后,还有一个坑,[9][9]这个位置没有搜到就print()了,所以在print()中要特判一下。

void print()
{
    if(ans[9][9]==0)
    for(int i=1;i<=9;i++)
    {
        if(!v[0][9][i]&&!v[1][9][i]&&!v[2][9][i]&&!v[3][9][9])
        {
            ans[9][9]=i;
            break;
        }
    }//填最后的位置
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
            cout<<ans[i][j];
        cout<<endl;
    }
}

然后愉快地交上去,AC了!!!

猜你喜欢

转载自blog.csdn.net/zhangchizc/article/details/103538111
今日推荐