POJ 2676 - Sudoku


问题描述

九宫格问题,也有人叫数独问题

把一个9行9列的网格,再细分为9个 3*3 的子网格,要求每行、每列、每个子网格内都只能使用一次 1~9 中的一个数字,即每行、每列、每个子网格内都不允许出现相同的数字。

0是待填位置,其他均为已填入的数字。

要求填完九宫格并输出(如果有多种结果,则只需输出其中一种)

如果给定的九宫格无法按要求填出来,则输出原来所输入的未填的九宫格。

解题思路

DFS试探,失败则回溯

用三个数组进行标记每行、每列、每个子网格已用的数字,用于剪枝:

bool row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了
bool col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了
bool grid[10][10];   //grid[k][x] 标记在第k个3\*3子格中数字z是否出现了

row 和 col的标记比较好处理,关键是找出grid子网格的序号与 行i列j的关系,

即要知道第i行j列的数字是属于哪个子网格的。

首先我们假设子网格的序号如下编排:

由于 1<=ij<=9,我们有: (其中 / 是C++中对整数的除法)

a= i/3 , b= j/3 ,根据九宫格的 行列 与 子网格 的 关系,我们有:

不难发现 3a+b=k3*(i/3)+j/3=k

又我在程序中使用的数组下标为 1~9,grid编号也为 1~9

因此上面的关系式可变形为 3*((i-1)/3)+(j-1)/3+1=k

有了这个推导的关系式,问题的处理就变得非常简单了,直接DFS即可

AC 源码

//Memory Time 
//184K  422MS 

#include<iostream>
using namespace std;

int map[10][10]; //九宫格

bool row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了
bool col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了
bool grid[10][10];   //grid[k][x] 标记在第k个3*3子格中数字z是否出现了

                     //(这里说明的字母不代表下面程序中的变量)

bool DFS(int x,int y)
{
    if(x==10)
        return true;

    bool flag=false;

    if(map[x][y])
    {
        if(y==9)
            flag=DFS(x+1,1);
        else
            flag=DFS(x,y+1);

        if(flag)  //回溯
            return true;
        else
            return false;
    }
    else
    {

        int k=3*((x-1)/3)+(y-1)/3+1;

        for(int i=1;i<=9;i++)   //枚举数字1~9填空
            if(!row[x][i] && !col[y][i] && !grid[k][i])
            {
                map[x][y]=i;

                row[x][i]=true;
                col[y][i]=true;
                grid[k][i]=true;

                if(y==9)
                    flag=DFS(x+1,1);
                else
                    flag=DFS(x,y+1);

                if(!flag)   //回溯,继续枚举
                {
                    map[x][y]=0;

                    row[x][i]=false;
                    col[y][i]=false;
                    grid[k][i]=false;
                }
                else
                    return true;
            }
    }
    return false;
}

int main(int i,int j)
{
    int test;
    cin>>test;
    while(test--)
    {
        /*Initial*/

        memset(row,false,sizeof(row));
        memset(col,false,sizeof(col));
        memset(grid,false,sizeof(grid));

        /*Input*/

        char MAP[10][10];
        for(i=1;i<=9;i++)
            for(j=1;j<=9;j++)
            {
                cin>>MAP[i][j];
                map[i][j]=MAP[i][j]-'0';

                if(map[i][j])
                {
                    int k=3*((i-1)/3)+(j-1)/3+1;
                    row[i][ map[i][j] ]=true;
                    col[j][ map[i][j] ]=true;
                    grid[k][ map[i][j] ]=true;
                }
            }

        /*Fill the Sudoku*/

        DFS(1,1);

        for(i=1;i<=9;i++)
        {
            for(j=1;j<=9;j++)
                cout<<map[i][j];
            cout<<endl;
        }
    }
    return 0;
}

相关资料


文章作者: EXP
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EXP !
 上一篇
POJ 3349 - Snowflake Snow Snowflakes POJ 3349 - Snowflake Snow Snowflakes
POJ 3349 - Snowflake Snow Snowflakes Time: 1000MS Memory: 65536K 难度: 初级 分类: 高效查找法 问题描述在n (n<100000)个雪花中判断是否存在两片完全相同
2011-06-11
下一篇 
POJ 1019 - Number Sequence POJ 1019 - Number Sequence
POJ 1019 - Number Sequence Time: 1000MS Memory: 10000K 难度: 初级 分类: 递推关系 问题描述有一串数字串,其规律为 1 12 123 1234 12345 123456 1234
2011-06-03
  目录