第十四届蓝桥杯青少组C++国赛[2023.5.28]第二部分编程题(4、 数独填数)

参考程序:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

char board[9][9];

// 检查在 (r,c) 填 num 是否有效
bool isValid(int r, int c, char num) {
    for (int i = 0; i < 9; ++i) {
        if (board[r][i] == num) return false;      // 同行
        if (board[i][c] == num) return false;      // 同列
        int br = (r/3)*3 + i/3;
        int bc = (c/3)*3 + i%3;
        if (board[br][bc] == num) return false;   // 同 3x3 宫
    }
    return true;
}

// 回溯 DFS 填数
bool dfs(int r, int c) {
    if (r == 9) return true; // 已填完所有行,成功

    if (board[r][c] != '.') {
        // 已有数字,移动到下一个格子
        if (c == 8) return dfs(r+1, 0);
        else return dfs(r, c+1);
    }

    for (char num = '1'; num <= '9'; ++num) {
        if (isValid(r, c, num)) {
            board[r][c] = num;
            if (c == 8) {
                if (dfs(r+1, 0)) return true;
            } else {
                if (dfs(r, c+1)) return true;
            }
            board[r][c] = '.'; // 回溯
        }
    }
    return false; // 无可行数字,回溯
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 输入 9 行
    for (int i = 0; i < 9; ++i) {
        string line;
        cin >> line;
        for (int j = 0; j < 9; ++j) board[i][j] = line[j];
    }

    dfs(0, 0); // 从左上角开始填数

    // 输出结果
    for (int i = 0; i < 9; ++i) {
        for (int j = 0; j < 9; ++j) cout << board[i][j];
        cout << '\n';
    }
    return 0;
}

参考程序2:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

char board[9][9];
int rowMask[9], colMask[9], boxMask[9];
vector<pair<int,int>> empties;

inline int boxIndex(int r, int c) {
    return (r/3)*3 + (c/3);
}

bool dfs() {
    // 找还未填且候选数最少的空格(启发式)
    int bestIdx = -1;
    int bestCount = 10;
    int bestMask = 0;
    for (int k = 0; k < (int)empties.size(); ++k) {
        int r = empties[k].first;
        int c = empties[k].second;
        if (board[r][c] != '.') continue; // 已被填过
        int mask = ~(rowMask[r] | colMask[c] | boxMask[boxIndex(r,c)]) & 0x1FF; // 9位掩码
        int cnt = __builtin_popcount(mask);
        if (cnt == 0) return false; // 无候选 -> 这条路失败,回溯
        if (cnt < bestCount) {
            bestCount = cnt;
            bestIdx = k;
            bestMask = mask;
            if (cnt == 1) break; // 已经是最优(1)可直接尝试
        }
    }

    if (bestIdx == -1) {
        // 没有空格,解出
        return true;
    }

    int r = empties[bestIdx].first;
    int c = empties[bestIdx].second;
    int b = boxIndex(r,c);

    // 依次尝试 bestMask 中的每个候选数字(低位表示数字1)
    int mask = bestMask;
    while (mask) {
        int bit = mask & -mask; // 取最低位 2^d
        int d = __builtin_ctz(bit); // d in [0..8], 对应数字 (d+1)
        mask ^= bit;

        // 放置 d+1
        board[r][c] = char('1' + d);
        rowMask[r] |= (1 << d);
        colMask[c] |= (1 << d);
        boxMask[b] |= (1 << d);

        if (dfs()) return true;

        // 撤销
        board[r][c] = '.';
        rowMask[r] &= ~(1 << d);
        colMask[c] &= ~(1 << d);
        boxMask[b] &= ~(1 << d);
    }

    return false;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 读取 9 行,每行可能含空格,保留数字或 '.' 字符直至获得 9 个有效字符
    for (int i = 0; i < 9; ++i) {
        string line;
        if (!getline(cin, line)) return 0; // 非法输入或 EOF
        string filtered;
        for (char ch : line) {
            if (ch == '.' || (ch >= '1' && ch <= '9')) filtered.push_back(ch);
            if (filtered.size() == 9) break;
        }
        // 若本行过滤后不足9个字符,继续读接下来的行拼满(提高对不规范输入的容错)
        while (filtered.size() < 9) {
            string extra;
            if (!getline(cin, extra)) break;
            for (char ch : extra) {
                if (ch == '.' || (ch >= '1' && ch <= '9')) filtered.push_back(ch);
                if (filtered.size() == 9) break;
            }
        }
        if (filtered.size() != 9) {
            // 如果输入仍然异常,填充 '.' 保证程序不会越界(实际题目不会出现)
            filtered.resize(9, '.');
        }
        for (int j = 0; j < 9; ++j) board[i][j] = filtered[j];
    }

    // 初始化掩码与空格列表
    fill(begin(rowMask), end(rowMask), 0);
    fill(begin(colMask), end(colMask), 0);
    fill(begin(boxMask), end(boxMask), 0);
    empties.clear();

    for (int i = 0; i < 9; ++i) {
        for (int j = 0; j < 9; ++j) {
            char ch = board[i][j];
            if (ch >= '1' && ch <= '9') {
                int d = ch - '1';
                int b = boxIndex(i,j);
                rowMask[i] |= (1 << d);
                colMask[j] |= (1 << d);
                boxMask[b] |= (1 << d);
            } else {
                board[i][j] = '.';
                empties.emplace_back(i,j);
            }
        }
    }

    bool ok = dfs();
    if (!ok) {
        // 按题意不会发生(保证有效且唯一),但安全处理
        cout << "No solution\n";
        return 0;
    }

    // 输出结果:9 行,每行 9 个数字,无空格
    for (int i = 0; i < 9; ++i) {
        for (int j = 0; j < 9; ++j) cout << board[i][j];
        cout << '\n';
    }
    return 0;
}
相关推荐
Starry_hello world21 分钟前
C++ 线程 (3)
c++
雍凉明月夜39 分钟前
c++ 精学笔记记录Ⅲ
c++·笔记·学习
oioihoii1 小时前
C++共享内存小白入门指南
java·c++·算法
布茹 ei ai1 小时前
QtWeatherApp - 简单天气预报软件(C++ Qt6)(附源码)
开发语言·c++·qt·开源·开源项目·天气预报
Bruce_kaizy1 小时前
c++图论————图的基本与遍历
c++·算法·图论
Zmm147258369_1 小时前
好用的PC耐力板机构
c++
LinHenrY12271 小时前
初识C语言(编译和链接)
c语言·开发语言·蓝桥杯
_OP_CHEN1 小时前
【算法基础篇】(三十五)图论基础之最小生成树:从原理到实战,彻底吃透 Prim 与 Kruskal 算法
算法·蓝桥杯·图论·最小生成树·kruskal算法·prim算法·acm/icpc
Code Slacker1 小时前
LeetCode Hot100 —— 普通数组(面试纯背版)(五)
数据结构·c++·算法·leetcode·面试
秦苒&2 小时前
【C语言】详解数据类型和变量(一):数据类型介绍、 signed和unsigned、数据类型的取值范围、变量、强制类型转换
c语言·开发语言·c++·c#