楼主: cuicg

[SQL] 用SQL或PL/SQL求解数独,替三思发帖。

[复制链接]
论坛徽章:
0
41#
发表于 2021-7-22 16:47 | 只看该作者
本帖最后由 wxy0327 于 2021-7-22 16:49 编辑
newkid 发表于 2008-10-18 03:18
[ 本帖最后由 newkid 于 2008-10-18 05:24 编辑 ]

我用https://baike.baidu.com/item/%E4 ... 13848819?fr=aladdin 测试 单机 120毫秒,已经是我所看到最快的DB解决方案了。大神能改成postgresql的么?

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
42#
发表于 2021-7-22 23:32 | 只看该作者
wxy0327 发表于 2021-7-22 16:47
我用https://baike.baidu.com/item/%E4 ... 13848819?fr=aladdin 测试 单机 120毫秒,已经是我所看 ...

postgresql是最接近oracle的数据库,实现了大部分PL/SQL的功能,所以肯定是没问题的。你试过了没有?如果不行是卡在哪里?
我手头没有装pg, 没法测试,要不你可以请OO帮忙测试。

使用道具 举报

回复
论坛徽章:
0
43#
发表于 2021-7-23 13:29 来自手机 | 只看该作者
数独 has been overlooked too long for its role in logical thinking and programming learning.  Combined with SQL, it can be an easy topic for 3rd grader to start learning some logical flow and simple programming.  For example, how many valid settings to put 1-9 into the 9x9 grid?  In SQL, it is simply, select Xi, ... from Ti, ... where Xi in (1,2,3,4,5,6,7,8,9) ... and Xi<>Xi ... ;   Note 1<=i,j<=81 and i,j are peer pairs.  To further solve a given problem, add detailed given conditions in the where clause as much as possible, eg, X1=5,...X81=2.  Of course it can provide many challenges as one wish with growing age.

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
44#
发表于 2021-7-23 21:20 | 只看该作者
jihuyao 发表于 2021-7-23 13:29
数独 has been overlooked too long for its role in logical thinking and programming learning.  Combin ...

如果不用PL/SQL,单纯用SQL来实现还是有一定挑战的。荷兰有位老兄提供了一种非常简洁的写法,我自己写了个比较复杂的SQL, 但是我的写法效率比他高。

使用道具 举报

回复
论坛徽章:
0
45#
发表于 2021-7-26 17:02 | 只看该作者
本帖最后由 wxy0327 于 2021-7-26 18:19 编辑
newkid 发表于 2021-7-22 23:32
postgresql是最接近oracle的数据库,实现了大部分PL/SQL的功能,所以肯定是没问题的。你试过了没有?如果不 ...

已改写,但比Oracle慢了4倍多,900毫秒左右
  1. DO $DECLARE

  2.    i int;
  3.    j int;
  4.    k  int;

  5.    s _varchar(10);
  6.    
  7.    used_c int[][]:=array_fill(0,array[9,9]);     --- in this column whether the number has been used
  8.    used_r int[][]:=array_fill(0,array[9,9]);     --- in this row whether the number has been used
  9.    used_a int[][]:=array_fill(0,array[9,9]);     --- in this area whether the number has been used
  10.    
  11.    area int[][]:=array_fill(0,array[9,9]);     ---- mapping from row, column to area
  12.    
  13.    v_cnt int :=0;
  14.    
  15.    slot_value int[][]:=array_fill(0,array[100,100]);
  16.    
  17.    slot_r int[];
  18.    slot_c int[];
  19.    
  20.    v_cnt2 int :=0;
  21.    
  22.    v_idx  int;
  23.    
  24.    slot_value_idx int[]=array_fill(1,array[60]);
  25.    
  26. BEGIN

  27.    s[1]:= '8        ';
  28.    s[2]:= '  36     ';
  29.    s[3]:= ' 7  9 2  ';
  30.    s[4]:= ' 5   7   ';
  31.    s[5]:= '    457  ';
  32.    s[6]:= '   1   3 ';
  33.    s[7]:= '  1    68';
  34.    s[8]:= '  85   1 ';
  35.    s[9]:= ' 9    4  ';

  36.    FOR i IN 1..9 LOOP
  37.        FOR j IN 1..9 LOOP
  38.            area[i][j] := (CEIL(i::numeric/3::numeric)-1)*3 + CEIL(j::numeric/3::numeric);
  39.                    --raise notice '%.%',i,j;
  40.                    --raise notice '%',area[i][j];
  41.        END LOOP;
  42.    END LOOP;

  43.    FOR i IN 1..9 LOOP
  44.        FOR j IN 1..9 LOOP
  45.            k := (case when TRIM(SUBSTRing(s[i],j,1))='' then '0' else TRIM(SUBSTRing(s[i],j,1)) end)::int;
  46.            IF k>0 THEN
  47.               used_c[j][k] :=1;
  48.               used_r[i][k] :=1;
  49.               used_a[area[i][j]][k] :=1;
  50.                           --raise notice 'aaaaaaaaaa';
  51.            END IF;
  52.        END LOOP;
  53.    END LOOP;
  54.    
  55.    FOR i IN 1..9 LOOP
  56.        FOR j IN 1..9 LOOP
  57.            IF SUBSTRing(s[i],j,1)=' ' THEN
  58.               v_cnt := v_cnt+1;
  59.               
  60.               v_cnt2 :=0;
  61.               
  62.               FOR k IN 1..9 LOOP
  63.                   IF used_c[j][k] = 0 AND used_r[i][k] = 0 AND used_a[area[i][j]][k] = 0 THEN  ---- possible value found for this slot
  64.                      v_cnt2 := v_cnt2 +1;
  65.                      slot_value[v_cnt][v_cnt2] := k;
  66.                                          --raise info 'slot_value[v_cnt][v_cnt2]: %',slot_value[v_cnt][v_cnt2];
  67.                   END IF;
  68.               END LOOP;
  69.               
  70.               IF v_cnt2 = 0 THEN
  71.                                  RAISE EXCEPTION '-20001,invalid sudoku at %,%',i,j;
  72.               END IF;
  73.               
  74.               IF v_cnt2 = 1 THEN        ---- there's only one value for this slot, it's the answer
  75.                  k := slot_value[v_cnt][1];
  76.                  used_c[j][k] :=1;
  77.                  used_r[i][k] :=1;
  78.                  used_a[area[i][j]][k] :=1;
  79.                  v_cnt := v_cnt - 1;
  80.                  
  81.                  s[i] := SUBSTRing(s[i],1,j-1) ||k|| SUBSTRing(s[i],j+1);
  82.                                  
  83.                                  --raise notice 'bbbbbbbbbb';

  84.               ELSE
  85.                  slot_r[v_cnt] := i;       ---- position of this slot
  86.                  slot_c[v_cnt] := j;
  87.               END IF;
  88.               
  89.            END IF;
  90.        END LOOP;
  91.    END LOOP;
  92.    
  93.    --raise notice '00000000000--%',s;
  94.    --raise notice '-----------------';
  95.    ---- initialize the value indexes of slots
  96.    /*v_idx := 1;
  97.    WHILE slot_value[v_idx][1] <>0 LOOP
  98.          slot_value_idx[v_idx] := 1;
  99.          -- DBMS_OUTPUT.PUT_LINE(v_idx||','||slot_value[v_idx].FIRST);
  100.          v_idx := v_idx+1;
  101.                  raise notice '111--%---%',v_idx,slot_value_idx[v_idx];
  102.                  -- DBMS_OUTPUT.PUT_LINE(v_idx||','||slot_value.NEXT[v_idx]);
  103.    END LOOP;*/
  104.    
  105.    --raise notice '111--%',slot_value_idx[60];
  106.    
  107.    v_idx := slot_value[1][1];

  108.    WHILE slot_value[v_idx][1] <>0 LOOP
  109.    
  110.                  --indx2:=1;
  111.    
  112.                  --raise notice '----------';

  113.          WHILE slot_value_idx[v_idx]<>0 LOOP      ---- try all values for this slot
  114.                  
  115.                            --raise notice '+++++++%',slot_value_idx[v_idx];
  116.                  
  117.                i := slot_r[v_idx];
  118.                j := slot_c[v_idx];
  119.                k := slot_value[v_idx][slot_value_idx[v_idx]];
  120.                            
  121.                            --raise notice 'v_idx : % i : % j : % k : %',v_idx,i,j,k;
  122.                            
  123.                            --raise notice 'v_idx : % used_c[j][k] : % uused_r[i][k] : % used_a[area[i][j]][k] : %',v_idx,used_c[j][k],used_r[i][k],used_a[area[i][j]][k];
  124.                
  125.                IF used_c[j][k] = 0 AND used_r[i][k] = 0 AND used_a[area[i][j]][k] = 0 THEN  ---- possible value found for this slot
  126.                                   --raise notice 'mmmmmmmmmm';
  127.                   used_c[j][k] := 1;
  128.                   used_r[i][k] := 1;
  129.                   used_a[area[i][j]][k] :=1;
  130.                   EXIT;
  131.                END IF;

  132.                            /*if slot_value[indx2][1] =0 and indx2>1 then
  133.                               EXIT;
  134.                            end if;*/
  135.                            
  136.                            --indx2:=indx2+1;
  137.                            slot_value_idx[v_idx] := case when slot_value[v_idx][slot_value_idx[v_idx]+1] = 0 then 0 else slot_value_idx[v_idx]+1 end;

  138.                            --raise notice '0000--%,%,%',v_idx,slot_value_idx[v_idx],case when slot_value[v_idx][slot_value_idx[v_idx]+1] = 0 then 0 else slot_value_idx[v_idx]+1 end;
  139.                            -- DBMS_OUTPUT.PUT_LINE(v_idx||','||slot_value_idx[v_idx]||','||slot_value[v_idx].NEXT(slot_value_idx[v_idx]));
  140.          END LOOP;

  141.          --raise notice '0000000--%',v_idx;
  142.          IF slot_value_idx[v_idx]=0 THEN   ---- all values tried but none is the answer
  143.                         --raise notice '-----------------';
  144.             
  145.                         slot_value_idx[v_idx] := slot_value[1][1];   --- reset the index of this slot
  146.                         
  147.             -- DBMS_OUTPUT.PUT_LINE(v_idx||','||slot_value[v_idx].FIRST);
  148.             v_idx := v_idx-1;     --- go back and release the last slot
  149.                         --raise notice '111111--%',v_idx;
  150.             IF slot_value[v_idx][1] =0 THEN      ----- no anwer found
  151.                            raise notice 'No Answer Found!';
  152.                EXIT;
  153.             END IF;
  154.             
  155.             i := slot_r[v_idx];
  156.             j := slot_c[v_idx];
  157.             k := slot_value[v_idx][slot_value_idx[v_idx]];
  158.             
  159.             used_c[j][k] := 0;
  160.             used_r[i][k] := 0;
  161.             used_a[area[i][j]][k] :=0;
  162.             
  163.                         --indx2:=indx2+1;
  164.             slot_value_idx[v_idx] := case when slot_value[v_idx][slot_value_idx[v_idx]+1] = 0 then 0 else slot_value_idx[v_idx]+1 end;
  165.                         
  166.                         --raise notice '1111--%,%,%',v_idx,slot_value_idx[v_idx],case when slot_value[v_idx][slot_value_idx[v_idx]+1] = 0 then 0 else slot_value_idx[v_idx]+1 end;
  167.                         
  168.          ELSE
  169.                         --raise notice '-----------------';
  170.                         --if v_idx+1 = 61 then
  171.                         --v_idx:=0;
  172.                         --else
  173.             v_idx := v_idx+1;
  174.                         --end if;
  175.                         --raise notice '222222--%',v_idx;
  176.             
  177.             IF slot_value[v_idx][1] =0 THEN      ----- all slots tried and found an answer

  178.                v_idx := slot_value[1][1];
  179.                            --raise notice '333333--%',v_idx;
  180.                WHILE slot_value[v_idx][1] <>0 and v_idx<>61 LOOP
  181.                            
  182.                      i := slot_r[v_idx];
  183.                      j := slot_c[v_idx];
  184.                      k := slot_value[v_idx][slot_value_idx[v_idx]];
  185.                      s[i] := SUBSTRing(s[i],1,j-1) || k || SUBSTRing(s[i],j+1);
  186.    
  187.                      v_idx := v_idx+1;

  188.                                          --raise notice 'sssssssssssss--%',s[i];
  189.                                          --raise notice '4444444--%',v_idx;
  190.                                          --raise notice 'slot_value_idx[v_idx] : %',slot_value_idx[v_idx];
  191.                                          --raise notice 'v_idx : % i : % j : % k : %',v_idx,i,j,k;
  192.                                          
  193.                END LOOP;
  194.                
  195.                raise notice 'Answer Found:';
  196.                FOR i IN 1..9 LOOP
  197.                    raise notice '%',s[i];
  198.                END LOOP;
  199.                
  200.                EXIT;

  201.             END IF;
  202.             
  203.          END IF;
  204.                  --raise notice '333--%',v_idx;
  205.    END LOOP;
  206.    
  207. END$;
复制代码

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
46#
发表于 2021-7-26 22:00 | 只看该作者
和PL/SQL几乎一摸一样嘛!
PL/SQL本身的性能不能和C,JAVA相比,它存在的意义不是用来做算法的,而是一种专门执行SQL的事务语言,类似SQL的粘合剂。

使用道具 举报

回复
论坛徽章:
0
47#
发表于 2021-7-27 16:45 来自手机 | 只看该作者
If remember correctly, that sql used recursive and later Oracle wrote an article to modify it in great details to make it harder to catch the basic logic.  The plain sql way may be too long in syntax but the logic is straight and easy too understand.  However, I would suggest to work on 4X4 grids (so Xi in 1,2,3,4) first.  Then sql will be much shortened but the logic is completely the same.  As 5th grader now I would add some skills like view, dynamic sql, hint, row number=1(for any given problem), etc to make coding easier and performance better.  In fact, for hard problems with chain link, there is no easy logical flow in procedure way (eg nested trial and error, brutal force, recursive function with changing data source arrays.  So the basic sql can be very handy and effective to the last step after procedure method identifies as many array elements as possible using well defined logics.  So instead of teaching “hello world”, teach how to count 2!, 4!, 9!, and their conditional combinations in standard SQL would definitely boost 3rd graders confidence for future programming learning in other languages.  

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
48#
发表于 2021-7-27 21:25 | 只看该作者
你说的” make it harder to catch the basic logic“是啥意思?改得比原来更难懂了?请给个链接。
你给自己的定位到底是五年级学生,还是编程老师?动手玩玩,把代码贴出来,比讲一堆原理更有趣。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
49#
发表于 2021-7-27 23:24 | 只看该作者

使用道具 举报

回复
论坛徽章:
0
50#
发表于 2021-7-28 02:29 来自手机 | 只看该作者
Like bear picking corns I am less organized than 5th grader.  I almost make no links in most topics.  But I do posted only one in sudoku website without marking link.  Let me try to find that one sometime later.  I do played a bunch of things all messed up together (but has not touched for quit long).  If someone wants further discussion maybe I can manage to sort something useful out.

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表