1317. Sudoku

解题技巧:1.数独每个格子记录自身还能填的数字,每次寻找能填数字数最少的格子填充数字。

     2.使用“禁用计数”的方式,记录每个格子某个数字被禁用的次数,以便脱离禁用后恢复可填性。

#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
using std::set;
using std::vector;

struct Elem {
    int num;
    set<int> lefts;
};

set<int> LEFTS;

const int maxn = 9;
char charMap[maxn][maxn+1];
Elem Map[maxn][maxn];

int ans[maxn][maxn];
int count;
int f[maxn][maxn][maxn + 1];

struct Cor {
    int r, c;
    Cor(int r_ = 0, int c_ = 0) : r(r_), c(c_) {}
    bool operator<(const Cor &cor) const {
        return (r < cor.r) || (r == cor.r && c < cor.c);
    }
};

set<Cor> unfills;

void init() {
    for (int i = 0; i < maxn; ++i) {
        for (int j = 0; j < maxn; ++j) {
            Map[i][j].num = 0;
            Map[i][j].lefts.insert(LEFTS.begin(), LEFTS.end());
        }
    }
    for (int i = 0; i < maxn; ++i) {
        for (int j = 0; j < maxn; ++j) {
            for (int k = 0; k < maxn; ++k) {
                f[i][j][k + 1] = 0;
            }
        }
    }
    count = 0;
    unfills.clear();
}

void input() {
    for (int i = 0; i < maxn; ++i) {
        scanf("%s", charMap[i]);
    }
}

void transform() {
    for (int i = 0; i < maxn; ++i) {
        for (int j = 0; charMap[i][j] != ‘\0‘; ++j) {
            if (charMap[i][j] != ‘_‘) {
                Map[i][j].num = charMap[i][j] - ‘0‘;
            } else {
                unfills.insert(Cor(i, j));
            }
        }
    }
}

void setting(int r, int c, int num) {
    Map[r][c].num = num;
    for (int i = 0; i < maxn; ++i) {
        Map[r][i].lefts.erase(num);
        ++f[r][i][num];
        Map[i][c].lefts.erase(num);
        ++f[i][c][num];
    }
    int beginr = r / 3 * 3;
    int beginc = c / 3 * 3;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            Map[i + beginr][j + beginc].lefts.erase(num);
            ++f[i + beginr][j + beginc][num];
        }
    }
}

void resume(int r, int c, int num) {
    Map[r][c].num = 0;
    for (int i = 0; i < maxn; ++i) {
        if (--f[r][i][num] == 0) Map[r][i].lefts.insert(num);
        if (--f[i][c][num] == 0) Map[i][c].lefts.insert(num);
    }
    int beginr = r / 3 * 3;
    int beginc = c / 3 * 3;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (--f[i+beginr][j+beginc][num] == 0) Map[i + beginr][j + beginc].lefts.insert(num);
        }
    }
}

void predeal() {
    for (int i = 0; i < maxn; ++i) {
        for (int j = 0; j < maxn; ++j) {
            if (Map[i][j].num != 0) {
                setting(i, j, Map[i][j].num);
            }
        }
    }
}

void dfs() {
    if (unfills.empty()) {
        // 达到一种目的状态
        ++count;
        if (count > 1) return;
        for (int i = 0; i < maxn; ++i) {
            for (int j = 0; j < maxn; ++j) {
                ans[i][j] = Map[i][j].num;
            }
        }
    } else {
        // 遍历unfills,寻找最小的
        set<Cor>::iterator iter = unfills.begin(), target = unfills.begin();
        while (iter != unfills.end()) {
            const Cor &cor1 = *iter;
            const Cor &cor2 = *target;
            if (Map[cor1.r][cor1.c].lefts.size() < Map[cor2.r][cor2.c].lefts.size()) {
                target = iter;
            }
            ++iter;
        }
        Cor cor = *target;
        unfills.erase(target);
        set<int> _lefts(Map[cor.r][cor.c].lefts);   //
        set<int>::iterator iter1 = _lefts.begin();
        while (iter1 != _lefts.end()) {
            int num = *iter1;
            setting(cor.r, cor.c, num);
            dfs();
            resume(cor.r, cor.c, num);
            ++iter1;
        }
        unfills.insert(cor);
    }
}

int main() {
    for (int i = 1; i <= 9; ++i) LEFTS.insert(i);
    int t;
    scanf("%d", &t);
    for (int tt = 1; tt <= t; ++tt) {
        // 初始化
        init();
        // 输入
        input();
        // 转化
        transform();
        // 预处理
        predeal();
        // 深搜
        dfs();

        if (count == 0) {
            printf("Puzzle %d has no solution\n", tt);
        } else if (count == 1) {
            printf("Puzzle %d solution is\n", tt);
            for (int i = 0; i < maxn; ++i) {
                for (int j = 0; j < maxn; ++j) {
                    printf("%d", ans[i][j]);
                }
                printf("\n");
            }
        } else if (count > 1) {
            printf("Puzzle %d has %d solutions\n", tt, count);
        }
        if (tt != t) printf("\n");
    }

    return 0;
}

  

时间: 2024-10-05 10:19:28

1317. Sudoku的相关文章

Sicily 1317. Sudoku

1317. Sudoku Constraints Time Limit: 10 secs, Memory Limit: 32 MB Description Sudoku is a placement puzzle. The goal is to enter a symbol in each cell of a grid, most frequently a 9 x 9 grid made up of 3 x 3 subgrids. Each row, column and subgrid mus

Sicily1317-Sudoku-位运算暴搜

最终代码地址:https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1317.c 这题博主刷了1天,不是为了做出来,AC之后在那死磕性能... 累积交了45份代码,纪念一下- - 以上展示了从1.25s优化到0.03s的艰苦历程... 来看题目吧,就是一个数独求解的题: 1317. Sudoku Constraints Time Limit: 10 secs, Memory Limit: 32 MB Descript

编程题目分类(剪辑)

1. 编程入门 2. 数据结构 3. 字符串 4. 排序 5. 图遍历 6. 图算法 7. 搜索:剪枝,启发式搜索 8. 动态规划/递推 9. 分治/递归 10. 贪心 11. 模拟 12. 算术与代数 13. 组合问题 14. 数论 15. 网格,几何,计算几何 [编程入门] PC 110101, uva 100, The 3n+1 problem, 难度 1 PC 110102, uva 10189, Minesweeper, 难度 1 PC 110103, uva 10137, The T

(转)sicily题目分类

Sicily题目分类 ·         [数据结构/图论] 1310 Right-Heavy Tree   笛卡尔树相关,复杂度O(N)或O(NlogN). ·1426 Phone List         电话号码前缀检索,trie树相关. ·1443 Printer Queue      基本队列操作. ·1149 等价表达式         判断表达式是否等价(递归求解) ·1136 山海经             n长序列里求m次区间询问的最大连续子区间和.线段树/RMQ ·1252

LeetCode37 Sudoku Solver

题目: Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by the character '.'. You may assume that there will be only one unique solution. A sudoku puzzle... ...and its solution numbers marked in red.  (Hard)

*Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by the character '.'. You may assume that there will be only one unique solution. A sudoku puzzle... ...and its solution numbers marked in red. public clas

Valid Sudoku

Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be partially filled, where empty cells are filled with the character '.'. A partially filled sudoku which is valid. Note:A valid Sudoku board (partially

[LeetCode]Valid Sudoku

检测数独是否合格. 思路: 填充一遍就知道是否合格. 基本暴力搜索的思想. 1 /*************************************************************************************************** 2 Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. 3 The Sudoku board could be parti

POJ Sudoku 数独填数 DFS

题目链接:Sudoku Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18105   Accepted: 8772   Special Judge Description Sudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smaller squares 3x3 as shown on the Fig