花了1晚上diy的matlab解数独算法,很好理解!

花了1晚上diy的matlab解数独算法,很好理解!



前言

老婆最近迷上了数独,还给我拍了张照片,初步了解了规则之后,试着玩了一下,浪费了半个小时还做不出来,于是想到了用matlab算。
据她自述,花了不止3个下午了,还没做出来。感兴趣的同学可以笔算一下!反正我没这个耐心

提示:小白diy的代码,不够优美,但很好懂

一、数独的规则

在9×9的方阵中,根据已有数字,在空位上填入1~9,使得:
1.同一行数字不重复;
2.同一列数字不重复;
3.粗线所分隔出的9宫格同一格内数字不重复。

二、算法

1.思路

一开始按枚举法,走迷宫的思路,从左至右,从上至下测试,遇到走不下去,就换数字重新走,结果这种思路机器一直都在运行,算法复杂度太高(70多个格子,每个格子平均3-4个可能性);
请教了老婆,才知道,一般人在做数独时,是先把确定的填下,再挑解少的试。于此得到启发:
1.先算每个格子的解集;
2.只有一个解的,那肯定是答案,就先填入,但不是都填,而是随机选一格,填入;
3.如果最少的都是多个解,就在解少的格子中随机选一格填入解空间的第一个数;
4.前面填过数字的格,它的解集中需要删除已经填过的数。
4.一次填一个数,填完了如果还有空格,就继续按上述法则填空;
5.如果按上述法则,填不下去了,说明路子走错了,就清空方阵重新开始上述步骤。
由于有“随机选一格”存在,算法往往不会超过2秒,就能给出正确答案。

2.流程图

Created with Raphaël 2.2.0 开始 读取数据 计算各空格的解集、解的个数 是否有格子是唯一解 随机选择这些格子中的一个, 如果是1个解就填入, 如果是多个解就填入第1个, 填入的数字从解集删除 方阵是否有改变 方阵是否有空格 结束并输出答案 是否有格子是唯二解 ........ 是否有格子是唯九解 yes no yes no yes no yes no yes no yes no

3.Matlab代码

首先自定义一个function,输入A表示方阵,i表示行序号,j表示列序号,能够计算空格的解集data:

function [data] = ketianrushu(A,i,j)
if A(i,j)==0
    if i<=3&&j<=3 %在a11
        a11=A(1:3,1:3);
        paichu = [a11(a11~=0)];
    else if i<=3&&j<=6 %在a12
            a12=A(1:3,4:6);
            paichu = [a12(a12~=0)];
        else if i<=3&&j<=9 %在a13
                a13=A(1:3,7:9);
                paichu = [a13(a13~=0)];
            else if i<=6&&j<=3 %在a21
                    a21=A(4:6,1:3);
                    paichu = [a21(a21~=0)];
                else if i<=6&&j<=6 %在a22
                        a22=A(4:6,4:6);
                        paichu = [a22(a22~=0)];
                    else if i<=6&&j<=9 %在a23
                            a23=A(4:6,7:9);
                            paichu = [a23(a23~=0)];
                        else if i<=9&&j<=3 %在a31
                                a31=A(7:9,1:3);
                                paichu = [a31(a31~=0)];
                            else if i<=9&&j<=6 %在a32
                                    a32=A(7:9,4:6);
                                    paichu = [a32(a32~=0)];
                                else
                                    a33=A(7:9,7:9);
                                    paichu = [a33(a33~=0)];
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    x=A(i,:);
    paichuhang = [x(find(x~=0))]';
    %不与所在列重复
    x=A(:,j);
    paichulie = [x(find(x~=0))];
    pc = union(union(paichu,paichuhang),paichulie);
    psb = [1,2,3,4,5,6,7,8,9];
    data =  setdiff(psb, pc);
else
    data=[];
end

再自定义另一个function,能把格子的序号k(1~81)映射为i,j(行序号、列序号):

function [i,j] = yingshe(k)
%yingshe 把k转化为i j
%   此处显示详细说明
if mod(k,9)~=0
    i=floor(k/9)+1;
    j=k-9*(i-1);
else
    i=k/9;
    j=9;
end


然后是主程序。

A=[5,7,0,0,1,0,3,0,0;
    0,0,0,5,0,0,9,0,7;
    8,3,0,0,0,0,0,0,0;
    0,0,0,0,3,0,0,2,0;
    6,0,0,4,0,5,0,0,9;
    0,1,0,0,6,0,0,0,0;
    0,0,0,0,0,7,0,0,4;
    2,0,5,0,0,0,0,9,0;
    0,0,7,0,5,0,0,1,2;]
A0=A;
data = cell(1,81);
len_data = zeros(1,81);

while ismember(0,A)
    for k=1:81
        [i,j]=yingshe(k);
        if A0(i,j)==0
            data{k}=ketianrushu(A,i,j);
        end
    end %计算当前矩阵各空格的可填入数
    for k=1:81
        len_data(k)=length(data{k});
    end %计算当前矩阵各空格可填入数个数
    A1=A;
    if ismember(1,len_data) %有唯一解时
        id = find(len_data==1);%算出都有哪些格有唯一解
        id_suiji = id(ceil(rand*length(id)));%随机选一格填数
        [i,j] = yingshe(id_suiji);%算出这一格的行列
        A(i,j) = data{id_suiji};%直接填入这一格可以填的唯一数
        data{id_suiji}=[];%这一格可以填的唯一数删除;
    else if ismember(2,len_data) %最少的有两个解时
            id = find(len_data==2);%算出都有哪些格有唯二解
            id_suiji = id(ceil(rand*length(id))); %随机选一格填数
            [i,j] = yingshe(id_suiji);%算出这一格的行列
            A(i,j) = data{id_suiji}(1);%直接填入这一格可以填的第一个数
            data{id_suiji}(1)=[];%这一格可以填的第一个数删除
        else if ismember(3,len_data) %最少的有三个解时
                id = find(len_data==3);%算出都有哪些格有唯三解
                id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                [i,j]=yingshe(id_suiji);%算出这一格的行列
                A(i,j) = data{id_suiji}(1);
                data{id_suiji}(1)=[];%这一格可以填的第一个数删除
            else if ismember(4,len_data)
                    id = find(len_data==4);%算出都有哪些格有唯四解
                    id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                    [i,j]=yingshe(id_suiji);%算出这一格的行列
                    A(i,j) = data{id_suiji}(1);
                    data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                else if ismember(5,len_data)
                        id = find(len_data==5);%算出都有哪些格有唯五解
                        id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                        [i,j]=yingshe(id_suiji);%算出这一格的行列
                        A(i,j) = data{id_suiji}(1);
                        data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                    else if ismember(6,len_data)
                            id = find(len_data==6);%算出都有哪些格有唯六解
                            id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                            [i,j]=yingshe(id_suiji);%算出这一格的行列
                            A(i,j) = data{id_suiji}(1);
                            data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                        else if ismember(7,len_data)
                                id = find(len_data==7);%算出都有哪些格有唯七解
                                id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                                [i,j]=yingshe(id_suiji);%算出这一格的行列
                                A(i,j) = data{id_suiji}(1);
                                data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                            else if ismember(8,len_data)
                                    id = find(len_data==8);%算出都有哪些格有唯八解
                                    id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                                    [i,j]=yingshe(id_suiji);%算出这一格的行列
                                    A(i,j) = data{id_suiji}(1);
                                    data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                                else if ismember(9,len_data)
                                        id = find(len_data==9);%算出都有哪些格有唯九解
                                        id_suiji = id(ceil(rand*length(id)));%随机选一格填数
                                        [i,j]=yingshe(id_suiji);%算出这一格的行列
                                        A(i,j) = data{id_suiji}(1);
                                        data{id_suiji}(1)=[];%这一格可以填的第一个数删除
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end    
    if A1==A %如果经过以上操作,数字不再变化
        A=A0;%从头开始
    end
end
A



总结

运行上述代码,可以得到最初图中那道数独题目的答案是:
在这里插入图片描述
可惜最后我老婆说题目不是我自己做的。。。白瞎=。=

  • 13
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
MATLAB是一种强大的数值计算和图形处理环境,它非常适合编写算法决数学问题,包括数独问题。在MATLAB中,你可以利用其丰富的矩阵操作和逻辑控制结构来设计一个数独的程序。以下是一个简要的步骤和思路: 1. **定义数独的表示**:数独可以用一个9x9的矩阵来表示,其中0表示空白格,1到9表示数字,1-9的数组表示可能的数字。 2. **读取或生成数独题目**:可以从文件、用户输入或预定义的测试数据开始。 3. **初始化**:创建一个决方案矩阵,并用初始数字填充已知的部分。 4. **递归搜索算法**: - 使用回溯法(backtracking)是常见的方法,从空格开始尝试填入数字。 - 对每个空格进行循环,尝试填入1-9中的每一个数字。 - 检查填入后是否符合数独规则(每一行、每一列、每个宫格都不能有重复的数字)。 - 如果当前填入合法,递归检查下一行;如果不合法,回溯并尝试下一个数字。 5. **决过程优化**: - 可以使用启发式策略(如最小的候选数优先),提高搜索效率。 - 利用MATLAB的并行计算能力,对部分步骤进行并行化,加速求。 6. **结果验证**:将出的矩阵与标准的数独对比,确保正确性。 **相关问题**: 1. 如何在MATLAB中实现回溯法? 2. 数独的启发式策略有哪些可以在MATLAB中应用? 3. 怎样利用MATLAB的并行计算特性加速数独

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值