标签

PostgreSQL , 数独 , 求解 , 动态规划


背景

使用《PostgreSQL 生成任意基数数独 - 3》 提供的方法,可以生成有解数独。在不知道数独答案的情况下,如何暴力破解呢?

实际上可以修改一下《PostgreSQL 生成任意基数数独 - 2》 里面的随机生成数独的函数,破解数独。

破解数独函数如下

create or replace function resolve_sudoku(      vsudoku int[]  -- 求解数独
) returns int[] as $$
declare      res int[];           -- 结果    dims int := array_length(vsudoku,1);   -- X,Y,BOX集合元素个数    dim int := sqrt(dims);  -- 基数  vxyb xyb[];          -- 存储每个像素在XYB方向上未填充的元素个数    x int;               -- 从xyb[]集合中,按指定方法选中一个像素。  X坐标    y int;               -- 从xyb[]集合中,按指定方法选中一个像素。  Y坐标    vloops int := 2*dims;     -- 计算N次(实际上就是随机多少次能覆盖到所有的值,值的取值空间为dims,通常来说执行DIMS次,能覆盖到所有的随机数)    vloop int :=0;            -- 计算N次计数器    cnt int := 0;             -- 统计当前数独总共填充了多少个元素    rand int;                 -- 随机值
begin      -- 求解  res := vsudoku;  loop    -- 生成每个像素X,Y,B方向的未知值个数    select comp_xyb(res, dim) into vxyb;    -- 选择下一个要填充的像素(根据未知值个数排行,从总未知值最多,按单轴最多的位置中随机取一个位置)    select ax,ay into x,y from     unnest(vxyb) t     where     t.x+t.y+t.b <> 0     order by     (t.x+t.y+t.b) desc ,     greatest(t.x,t.y,t.b) desc     limit 1;      -- 如果全部为0,0,0,说明已解完,返回res。    if not found then    raise notice '计算有解,计算%次,结束。', cnt;    return res;    end if;    -- 初始化以下计算循环次数    vloop := 0;    loop      -- 生成随机值      rand := 1+(random()*(dims-1))::int;      -- 这轮循环无法生成并返回空     if vloop >= vloops then      raise notice '本像素已循环%次,计算无解。已填充%个元素。无解数独如下: %', vloop, cnt, res;    -- return res;    return null;    end if;      -- 循环次数+1    vloop := vloop+1;      -- 横向验证      perform 1 where array(select res[x][generate_series(1,dims)]) && array[rand];      if found then      continue;      end if;      -- 纵向验证      perform 1 where array(select res[generate_series(1,dims)][y]) && array[rand];      if found then      continue;      end if;      -- BOX验证      perform 1 where     array(    select res[xx][yy] from     (select generate_series(((((x-1)/dim)::int)*dim)+1, ((((x-1)/dim)::int)*dim)+dim) xx) t1,     (select generate_series(((((y-1)/dim)::int)*dim)+1, ((((y-1)/dim)::int)*dim)+dim) yy) t2    ) && array[rand];      if found then      continue;      end if;      -- 这个像素值,通过验证      res[x][y] := rand;      -- raise notice 'res[%][%] %', x, y, rand;      -- 通过验证并跳出循环,找下一个需要填充的像素    cnt := cnt+1;    exit;      end loop;      end loop;
end;
$$ language plpgsql strict volatile;

例子

1、首先按难易程度生成几个数独

postgres=# select gen_sudoku_question(20);   gen_sudoku_question
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  {{1,6,7,9,5,8,4,3,2},{9,5,8,4,3,2,1,6,7},{4,3,2,1,6,7,9,5,8},{6,7,1,5,8,9,3,2,4},{5,8,9,3,2,4,6,7,1},{3,2,4,6,7,1,5,8,9},{7,1,6,8,9,5,2,4,3},{8,9,5,2,4,3,7,1,6},{2,4,3,7,1,6,8,9,5}}  {{1,0,7,9,0,8,4,3,2},{9,0,8,0,3,2,0,6,7},{4,3,2,1,6,7,0,5,8},{6,0,1,0,8,9,0,2,4},{5,0,9,3,2,4,0,7,1},{3,2,0,6,7,1,5,8,9},{7,1,0,0,0,5,0,4,3},{0,9,5,2,4,0,7,1,6},{0,4,3,7,0,6,8,9,5}}
(2 rows)  postgres=# select gen_sudoku_question(41);
NOTICE:  relation "tmp_sudoku" already exists, skipping  gen_sudoku_question
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  {{5,3,9,2,6,7,1,4,8},{1,4,8,5,3,9,2,6,7},{2,6,7,1,4,8,5,3,9},{9,5,3,7,2,6,8,1,4},{8,1,4,9,5,3,7,2,6},{7,2,6,8,1,4,9,5,3},{3,9,5,6,7,2,4,8,1},{4,8,1,3,9,5,6,7,2},{6,7,2,4,8,1,3,9,5}}  {{5,0,0,2,0,7,1,0,8},{0,4,0,0,0,9,0,6,7},{2,0,7,0,0,0,0,0,0},{9,0,3,0,2,6,8,1,4},{0,1,0,0,0,0,7,0,6},{0,0,6,0,0,0,0,5,3},{0,9,0,6,0,2,4,0,1},{4,8,0,0,9,0,6,7,2},{6,0,2,4,0,1,0,0,5}}
(2 rows)  postgres=# select gen_sudoku_question(51);
NOTICE:  relation "tmp_sudoku" already exists, skipping  gen_sudoku_question
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  {{3,4,5,8,1,6,2,9,7},{8,1,6,2,9,7,3,4,5},{2,9,7,3,4,5,8,1,6},{4,5,3,1,6,8,9,7,2},{1,6,8,9,7,2,4,5,3},{9,7,2,4,5,3,1,6,8},{5,3,4,6,8,1,7,2,9},{6,8,1,7,2,9,5,3,4},{7,2,9,5,3,4,6,8,1}}  {{0,4,5,0,0,6,2,9,0},{8,1,0,0,0,0,0,4,0},{2,0,0,3,4,0,8,0,6},{0,0,3,1,6,8,0,0,0},{0,0,8,0,0,0,4,5,0},{0,0,0,4,0,0,1,6,0},{0,0,0,0,0,1,0,0,9},{6,0,0,7,0,0,0,3,4},{0,0,0,0,0,0,0,0,1}}
(2 rows)

2、使用上面创建的函数破解数独
填充20个值的数独基本上秒解。

postgres=# select res from (select resolve_sudoku('{{1,0,7,9,0,8,4,3,2},{9,0,8,0,3,2,0,6,7},{4,3,2,1,6,7,0,5,8},{6,0,1,0,8,9,0,2,4},{5,0,9,3,2,4,0,7,1},{3,2,0,6,7,1,5,8,9},{7,1,0,0,0,5,0,4,3},{0,9,5,2,4,0,7,1,6},{0,4,3,7,0,6,8,9,5}}'::int[]) res from generate_series(1,100) ) t where t.res is not null ;
                                                                                          res
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  {{1,6,7,9,5,8,4,3,2},{9,5,8,4,3,2,1,6,7},{4,3,2,1,6,7,9,5,8},{6,7,1,5,8,9,3,2,4},{5,8,9,3,2,4,6,7,1},{3,2,4,6,7,1,5,8,9},{7,1,6,8,9,5,2,4,3},{8,9,5,2,4,3,7,1,6},{2,4,3,7,1,6,8,9,5}}
(1 row)

但是对于需要填充41个,51个的,这种暴力尝试的方式,跑1000次也解不出来。

还是需要一个非常行之有效的。

目前的暴力破解存在的问题,一个值一旦确定下来(XYB方向满足约束)之后,后面就不会去修正它,从而导致了一个错误后面的计算全是浪费的。增加了破解成本。

扩展

在数据库中执行计划也与之类似,目前大多数执行计划是静态的,一旦执行计划确定下来了,后面就只能按照执行计划执行,无法中途调整。

所以,动态执行计划也成为目前很多数据库优化器突破的方向,在执行过程中,根据执行过程中的统计信息,不断修正执行计划,达到最佳的目的。

实际上,导航也与之类似,如果你根据当前的路况规划好了导航,在行驶过程中,可能某些路段发生了变化(拥堵情况),静态导航就无法修正这样的问题,还是按一开始既定的线路行驶。而动态导航,可以根据实时路况进行修正,选择下一跳。

在生产中有很多类似的例子,比如数据路由,负载均衡等等。

PostgreSQL 生成任意基数数独 - 4相关推荐

  1. php 输出任意一个数,php 生成任意范围的水仙花数

    水仙花数(Narcissistic number)也被称为超完全数字不变数(pluperfect digital invariant, PPDI).自恋数.自幂数.阿姆斯壮数或阿姆斯特朗数(Armst ...

  2. python生成订单号或生成任意序列

    python生成订单号或生成任意序列 示例代码: import time# 生成订单号 def get_order_code():# 年月日时分秒+time.time()的后7位order_no = ...

  3. VBA实现两种方法生成任意概率分布的随机数

    引子 一把武器的品质有分为最下级.下级.中级.上级.最上级五档,我希望在击杀一只怪物的时候,这把武器的掉率:最下级>下级>中级>上级>最上级,问如何设计满足上面的需求? 在游戏 ...

  4. python随机生成车牌_Python实现随机生成任意数量车牌号

    之前做课设的时候舍友遇到了需要生成500w量级车牌号的问题,于是我便写了一个随机生成车牌号的程序,希望各位采纳. 注:Python实现 import random def chepaihao(len= ...

  5. crc生成多项式怎么算_利用system Verilog生成任意CRC多项式

    IC君的第43篇原创文章 之前有一篇文章讲了CRC串行和并行电路的实现:CRC算法的硬件电路实现:串行电路和并行电路. 有做过类似设计的同学问:有没有办法轻松愉快地生成任意CRC多项式的电路?我们在设 ...

  6. 我的Python脚本——生成任意波形并存为txt

    我的Python脚本--生成任意波形并存为txt 一. 脚本功能 根据采样点数,采样周期数等参数以及波形的数学表达式,生成任意波形 将波形数据转为指定位宽的二进制补码,然后存为txt 绘制原始波形和转 ...

  7. python批量生成图片_利用Python批量生成任意尺寸的图片

    实现效果 通过源图片,在当前工作目录的/img目录下生成1000张,分别从1*1到1000*1000像素的图片. 效果如下: 目录结构 实现示例 # -*- coding: utf-8 -*- imp ...

  8. python批量生成图_利用Python批量生成任意尺寸的图片

    实现效果 通过源图片,在当前工作目录的/img目录下生成1000张,分别从1*1到1000*1000像素的图片. 效果如下: 目录结构 实现示例 # -*- coding: utf-8 -*- imp ...

  9. python实现给定信号生成任意信噪比的带噪声信号

    python实现给定信号生成任意信噪比的带噪声信号 产生叠加高斯白噪声的带噪语音 功能: 输入x为需加噪的信号,是一个numpy的1D张量 输入snr为设定信噪比,单位为dB,是一个32为的float ...

  10. 软工个人项目之生成和求解数独

    软工个人项目之生成和求解数独 在这次完成个人项目的过程中,我第一次尝试了写csdn博客,用vs进行性能分析,在vs里面写单元测试,这次收获了很多.虽然还有很多需要改进的地方,但我会做得越来越好的~ 1 ...

最新文章

  1. 【IDAX投研中心】BCH诞生一周年 “青出于蓝而胜于蓝”吗?
  2. Hive学习笔记 —— Hive的体系结构
  3. 四个角度教你评估一个产品的用户体验好坏 | PMCAFF
  4. C++ int转string的几种方法比较
  5. 通过高速计算机网络和多媒体,计算机网络作业及答案.doc
  6. python gui编程 从入门到项目实战_python GUI编程 QT5开发项目实战
  7. 从保证业务不中断,看网关的“前世今生”
  8. 用java实现学生管理系统
  9. 反向传播的目的,及其为什么要从后向前计算梯度
  10. python编程代码画画_分享给大家几段有趣的代码,学会python画画可以不用自己动手啦...
  11. redis过期策略有哪些?内存淘汰机制有哪些?
  12. 几种ESB(企业服务总线)介绍
  13. 微信浮窗是不是服务器保存,微信浮窗,能解决小程序留存难题吗?
  14. 3G模块SIM5360E实现拨号上网功能
  15. prometheus 监控告警安装与设置
  16. 3D数学基础——欧拉角与万向节死锁
  17. 模型量化(6):Yolov5 QAT量化训练
  18. pycharm安装与配置Pyqt5
  19. 你的设计应该「所见即所得」
  20. 【IoT】产品设计:硬件产品外观样品设计工艺及要求(手板)

热门文章

  1. 自学Java怎么入门
  2. 软件测试流程(完整版)
  3. 方舟基础物品指令代码大全
  4. 用计算机关闭无线网络连接,我的DELL笔记本电脑无线网络已关闭,怎么进行再连接?...
  5. ADT版本查看,This Android SDK requires Andr...ate ADT to the latest问题
  6. APP性能测试之jmeter
  7. 用iPhone打造个人的GTD(Get Things Done)实践
  8. linux麒麟认证,【麒麟在线讲堂】优麒麟生物特征认证系统-03驱动开发
  9. 设计模式之禅(第2版)PDF资源分享
  10. XSD文件详解(以Maven为例)