标签

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. oracle无创建directory权限,【DIRECTORY】普通用户创建Oracle DIRECTORY数据库对象的权限需求及探索...
  2. 不降低scipy版本解决AttributeError: module ‘scipy.misc‘ has no attribute ‘imresize‘问题
  3. IDEA 中比较骚后缀补全技巧!你可能没用过
  4. 网站外链如何发布才能更快的得到高排名呢?
  5. Java NIO之套接字通道
  6. python 爬取全量百度POI
  7. mysql去掉两个最高分_MySQL中查询、删除重复记录的方法大全
  8. 一文了解11个常见的多变量分析方法!
  9. KindEditor实现上传图片与回显
  10. 搭建服务器处理系统(基于netty),基于Netty的农业物联网服务器系统设计.PDF
  11. NoSQL:文档数据库
  12. 软件架构-事件驱动架构
  13. 「luogu4093」[HEOI2016/TJOI2016]序列
  14. 多个Excel文件独立窗口打开方式(一键解决)
  15. bin是什么文件,要如何打开?
  16. STC12C5A60S2独立PWM
  17. 人到底是为了什么活着?
  18. 机器学习分类器模型评价指标
  19. 【研究生】Yann LeCun、吴恩达等的2019年AI趋势预测
  20. Docker与k8s

热门文章

  1. 凯撒密码加密算法python_想偷WiFi?万能钥匙不行?试试用python一键破解!
  2. 软件测试面试题 背完面试没问题 亲测
  3. uniapp快速开发微信、支付宝app支付
  4. 网页版office服务器,Office 网页版服务说明
  5. MyEclipse中SVN分支合并到主干
  6. bodymovin_基于Bodymovin在Vue上渲染After Effects动画
  7. 专访数据挖掘领头人韩家炜教授:不要迷信权威,做学问要秉承「三个真实」...
  8. 莫烦python进化算法_使用遗传算法解决TSP问题(莫烦python 学习笔记)
  9. 吃鸡游戏计算机配置,运行端游吃鸡要什么配置
  10. python飞机大战源码素材包_Python飞机大战实战项目案例