• 数独问题的介绍及POJ 2676-Sudoku(dfs+剪枝)


    知道是数独问题后犹豫了一下要不要做(好像很难的样纸==。),用dfs并剪枝,是一道挺规范的搜索题。

    先介绍以下数独吧~

    数独(Sudoku)是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格 的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。 每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。

    有一种求解数独问题的方案是“候选数字法”,就是在待填充的格子中填写不会造成行重复、列重复、块重复的数字,有的时候存在多个这样的数字,那么我们可以随机选取一个,如果待填充的格子中填写任何一个数字都会造成某种重复的发生,则说明这个问题没有解,也就是这不是一个数独问题。

    想要更加深入了解的同学可以点此链接:http://www.cnblogs.com/grenet/archive/2013/06/19/3138654.html

    下面来说说POJ的这道题吧!

    题目大意:

      给你一个数独,让你填数:

    1.每行的九个数字互不相同;

    2.每列的九个数字各不相同;

    3.被分成的3*3的小矩阵中的九个数字互不相同;

    输出完成后的数表,若不能满足上述条件,则输出原图。

    解题思路:

    DFS。。失败了回溯~

    从小优女神那里看到的存储方式(觉得很是方便呀!)

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

    bool row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了

    bool col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了

    bool small[10][10];   //small[k][x] 标记在第k个3*3子格中数字z是否出现了

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

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

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

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

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

    不难发现 3a+b=k

    即 3*(i/3)+j/3=k

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

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

    这样我们就能记录k个3*3子格中数字z是否出现了:

    下面是我的代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<ctime>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<cstdlib>
      8 #include<vector>
      9 #define inf 1<<25
     10 #define LL long long
     11 using namespace std;
     12 int row[10][10];
     13 int col[10][10];
     14 int map[10][10];
     15 int small[10][10];
     16 int f(int x,int y)
     17 {
     18     return 3*((x-1)/3)+(y-1)/3+1;
     19 }
     20 void init()
     21 {
     22     int i,j;
     23     char ch;
     24     memset(row,0,sizeof(row));
     25     memset(col,0,sizeof(col));
     26     memset(small,0,sizeof(small));
     27     for(i=1; i<=9; i++)
     28         {
     29             for(j=1; j<=9; j++)
     30             {
     31                 scanf("%c",&ch);
     32                 map[i][j]=ch-'0';
     33                 if(map[i][j])
     34                 {
     35                     int k;
     36                     k=f(i,j);
     37                     row[i][map[i][j]]=1;
     38                     col[j][map[i][j]]=1;
     39                     small[k][map[i][j]]=1;
     40                 }
     41             }
     42             getchar();
     43         }
     44 }
     45 int dfs(int x,int y)
     46 {
     47     if(x==10)
     48         return 1;
     49     int flag=0;
     50     if(map[x][y])
     51     {
     52         if(y==9)
     53             flag=dfs(x+1,1);
     54         else
     55             flag=dfs(x,y+1);
     56         if(flag)
     57             return 1;
     58         else
     59             return 0;
     60     }
     61     else
     62     {
     63         int k=f(x,y);
     64         for(int i=1; i<=9; i++)
     65             if(!row[x][i] && !col[y][i] && !small[k][i])
     66             {
     67                 map[x][y]=i;
     68                 row[x][i]=1;
     69                 col[y][i]=1;
     70                 small[k][i]=1;
     71                 if(y==9)
     72                     flag=dfs(x+1,1);
     73                 else
     74                     flag=dfs(x,y+1);
     75                 if(!flag)
     76                 {
     77                     map[x][y]=0;
     78                     row[x][i]=0;
     79                     col[y][i]=0;
     80                     small[k][i]=0;
     81                 }
     82                 else
     83                     return 1;
     84             }
     85     }
     86     return 0;
     87 }
     88 int main()
     89 {
     90     int t;
     91     scanf("%d",&t);
     92     getchar();
     93     while(t--)
     94     {
     95         init();
     96         dfs(1,1);
     97         for(int i=1; i<=9; i++)
     98         {
     99             for(int j=1; j<=9; j++)
    100                 printf("%d",map[i][j]);
    101             printf("
    ");
    102         }
    103     }
    104     return 0;
    105 }
  • 相关阅读:
    CF div2 332 A
    vector resize 错误用法
    linux命令之 chown
    dlmalloc 编译 链接
    C++ 类 访问限制
    C++ 编译多态 运行多态
    libevent 编译 Windows
    浮点数小记
    NYOJ 435 棋盘覆盖(二)
    HDU 3555 Bomb 简单数位DP
  • 原文地址:https://www.cnblogs.com/PJQOOO/p/4074644.html
Copyright © 2020-2023  润新知