zoukankan      html  css  js  c++  java
  • 【POJ2676】Sudoku

    本题传送门

    本题知识点:深度优先搜索 + 回溯

    问题就是要让我们解决一个数独问题。如果你懂得怎么玩数独的话,那就很自然想到用暴力搜索去做题。(比如我就不会,所以先WA了一发quq)

    数独符合三个条件

    1. 同行里只有 1 ~ 9 这9个数字
    2. 同列里只有 1 ~ 9 这9个数字
    3. 在这9x9的方阵里有9个3x3的小方阵,每个小方阵里的9个数也只能是 1 ~ 9

    注意,这每行每列每小方阵的9个数各都是1个

    所以,我用了3个bool数组去存他们的状态

    数据很小

    2s我跑了700多ms就过了

    详细可见代码

    // POJ 2676
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    
    int T, tot;
    bool ok;
    bool row[10][10]; // 行 i,j 表示第 i 行上的 j 已填
    bool col[10][10]; // 列 i,j 表示第 i 列上的 j 已填
    bool kuang[10][10][10]; // 小框里 a,b 表示在哪个小框里 i,j 表示小框里的数
    char sudoku[10][10];
    
    void build(){
        // 注意要初始化
        tot = 0; ok = false;
        memset(row, false, sizeof(row));
        memset(col, false, sizeof(col));
        memset(kuang, false, sizeof(kuang));
        for(int i = 1; i <= 9; i++) scanf("%s", sudoku[i] + 1);
    
        for(int i = 1; i <= 9; i++) // 行
            for(int j = 1; j <= 9; j++) // 列
                if(sudoku[i][j] != '0'){
                    row[i][ sudoku[i][j] - '0' ] = true;
                    col[j][ sudoku[i][j] - '0' ] = true;
    
                    // 一个9x9的格子里有9个3x3的小格子,向上取整就可以找到小格子的位置啦(向下取整也可以,不过向下取整这里的3是1,不好处理,于是我用向上取整)
                    int a = ceil(i / 3.0), b = ceil(j / 3.0);
                    kuang[a][b][ sudoku[i][j] - '0' ] = true;
                }
                else tot++;
    
    }
    
    void dfs(int h, int w, int cnt){ // cnt 记录当前还有多少个格子未填
        // 注意此尾都要加上 return
        if(cnt == 0){ ok = true; return ; } // 都填完了,返回
        if(w == 10) { dfs(h + 1, 1, cnt); return ; } // 该行填完了,进行下一行
        if(sudoku[h][w] != '0') { dfs(h, w + 1, cnt); return ; } // 该元素不是空的,继续进行搜索
        if(h == 10) return ; // 已经都搜索完 返回
    
        int a = ceil(h / 3.0); // 9个小框的行
        int b = ceil(w / 3.0); // 9个小框的列
    
        // 对于位置为'0'的格子进行填数
        for(int i = 1; i <= 9; i++){ // 该格子上的数字遍历数字
            if(!row[h][i] && !col[w][i] && !kuang[a][b][i]){
                // 更新状态
                sudoku[h][w] = i + '0';
                row[h][i] = true; col[w][i] = true; kuang[a][b][i] = true;
                dfs(h, w + 1, cnt - 1); // 未填的格子减 1
                if(ok) return ;
                // 回溯状态
                row[h][i] = false; col[w][i] = false; kuang[a][b][i] = false;
                sudoku[h][w] = '0';
            }
        }
    }
    
    int main()
    {
        scanf("%d", &T);
        while(T--){
            build();
            // 找到第一个没有填的格子
            for(int i = 1; i <= 9; i++){
                bool out = false;
                for(int j = 1; j <= 9; j++){
                    if(sudoku[i][j] == '0'){
    //                    printf("i:%d j:%d
    ", i, j);
                        dfs(i, j, tot);
                        out = true;
                        break;
                    }
                }
                if(out) break;
            }
    //        printf("tot:%d
    ", tot);
    //        cout << endl;
            for(int i = 1; i <= 9; i++)
                printf("%s
    ", sudoku[i] + 1);
        }
        return 0;
    }
    
    
  • 相关阅读:
    C++ | 继承(基类,父类,超类),(派生类,子类)
    C++ std::pair的用法
    派生类构造函数和多重继承的二义性问题
    C++vector and opencv Mat
    C++中union的使用方法
    C++中数组作为形参的方法
    在Python中使用OpenCV(CV2)对图像进行边缘检测
    你可能会用到的一些小程序效果、工具
    AI口算批改、练习小程序
    拍照搜题小程序
  • 原文地址:https://www.cnblogs.com/Ayanowww/p/11603558.html
Copyright © 2011-2022 走看看