解数独(C++版本)

数独是一个我们都非常熟悉的经典游戏,运用计算机我们可以很快地解开数独难题,现在有一些简单的数独题目,请编写一个程序求解。

如有多解,输出一个解

思路一 简单数独

复制代码
	通过找出空缺位置在行、列、3x3上的缺值,进行补充。
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int blockNum = 0, whileTime = 200;
    int shudu[9][9] = {0};
    bool fullFlag = false;

    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            cin >> shudu[i][j];

            if (0 == shudu[i][j]) {
                // isFull[i][j] = false;
                blockNum++;
            }
        }
    }

    while (!fullFlag && whileTime) {

        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (!shudu[i][j]) {

                    //缺少的为false,有的为true
                    bool numList[9] = {false};
                    int lackTime = 0;
                    int lackSet = -1;

                    /*
                    步骤一:找出当前位置所在行、列、块的缺值(numList)
                    */
                    //行,行标不变遍历列
                    for (int j_ = 0; j_ < 9; j_++) {
                        if (shudu[i][j_]) {
                            numList[shudu[i][j_] - 1] = true;
                        }
                    }

                    //列,列标不变遍历行
                    for (int i_ = 0; i_ < 9; i_++) {
                        if (shudu[i_][j]) {
                            numList[shudu[i_][j] - 1] = true;
                        }
                    }

                    //3x3,遍历所在块
                    for (int i_ = (i / 3); i_ < (i / 3 + 1) * 3; i_++) {
                        for (int j_ = (j / 3); j_ < (j / 3 + 1) * 3; j_++) {
                            if (shudu[i_][j_]) {
                                numList[shudu[i_][j_] - 1] = true;
                            }
                        }
                    }

                    /*
                    步骤二:判断当前位置的缺失值是否唯一
                    */
                    for (int k = 0; k < 9; k++) {
                        if (!numList[k]) {
                            lackTime++;
                            lackSet = k;
                        }
                    }
                    if (1 == lackTime) {
                        shudu[i][j] = lackSet + 1;
                        blockNum--;
                        whileTime++;
                        if (0 == blockNum) {
                            fullFlag = true;
                        }
                    }
                }
            }
        }

        whileTime--;
    }

    if (fullFlag) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                cout << shudu[i][j] << ' ';
            }
            cout << endl;
        }
    } else {
        cout << "解题失败!";
    }
    return 0;
}
复制代码
	代码使用了多次循环,寄希望与可以通过多轮迭代完成最终解答,但是无法处理多候选数情况、循环次数也可能冗余或不足。此外应对多候选时需要使用回溯机制。

思路二

复制代码
	引入回溯机制,当发现状态空间树上该路径无法得到正确解时,通过逐层回溯进行下一次尝试直到得到最终解。
cpp 复制代码
#include <iostream>
using namespace std;

bool isVilad(int MIX[9][9], int I, int J, int num) {

    int i = (I / 3 ) * 3;
    int j = (J / 3 ) * 3;

    //检查行
    for (int _j = 0; _j < 9; _j++) {
        if (num == MIX[I][_j])
            return false;
    }

    //检查列
    for (int _i = 0; _i < 9; _i++) {
        if (num == MIX[_i][J])
            return false;
    }

    //检查3x3
    for (int _i = i; _i < i + 3; _i++) {
        for (int _j = j; _j < j + 3; _j++) {
            if (num == MIX[_i][_j])
                return false;
        }
    }

    return true;

}

bool solve(int MIX[9][9]) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0 ; j < 9; j++) {

            //如果为空,则进行补充
            if (0 == MIX[i][j]) {

                for (int num = 1; num <= 9; num++) {
                    //尝试1~9
                    if (isVilad(MIX, i, j, num)) {
                        MIX[i][j] = num;

                        if (solve(MIX))
                            return true;

                        MIX[i][j] = 0;
                    }
                }
                return false;
            }
        }
    }

    return true;
}

int main() {
    int board[9][9];

    // 读取输入
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 9; j++)
            cin >> board[i][j];

    // 求解并输出
    if (solve(board)) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                cout << board[i][j];
                if (j < 8) cout << ' ';
            }
            cout << endl;
        }
    } else {
        cout << "返回False" << endl;
    }

    return 0;
}

思路三:

将前两者结合,即在迭代时,只从当前位置空缺的选项中选择,能提高一定时间?

或许,但是可能直接回溯更快,因为重复项会在第一次判断时直接PASS,从而不会增加过多时间。

相关推荐
玄同7651 分钟前
Python Random 模块深度解析:从基础 API 到 AI / 大模型工程化实践
人工智能·笔记·python·学习·算法·语言模型·llm
爱吃生蚝的于勒2 分钟前
【Linux】线程概念(一)
java·linux·运维·服务器·开发语言·数据结构·vim
Pluchon4 分钟前
硅基计划4.0 算法 简单模拟实现位图&布隆过滤器
java·大数据·开发语言·数据结构·算法·哈希算法
我命由我123454 分钟前
Java 泛型 - Java 泛型通配符(上界通配符、下界通配符、无界通配符、PECS 原则)
java·开发语言·后端·java-ee·intellij-idea·idea·intellij idea
符哥20085 分钟前
C++ 适合初学者的学习笔记整理
c++·笔记·学习
独断万古他化9 分钟前
【算法通关】前缀和:和为 K、和被 K整除、连续数组、矩阵区域和全解
算法·前缀和·矩阵·哈希表
yunsr10 分钟前
python作业3
开发语言·python
历程里程碑11 分钟前
普通数组-----除了自身以外数组的乘积
大数据·javascript·python·算法·elasticsearch·搜索引擎·flask
AI视觉网奇14 分钟前
blender 导入fbx 黑色骨骼
学习·算法·ue5·blender
星火开发设计15 分钟前
this 指针:指向对象自身的隐含指针
开发语言·数据结构·c++·学习·指针·知识