<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Decode360's Blog

    業精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      397 隨筆 :: 33 文章 :: 29 評論 :: 0 Trackbacks
    PLSQL解sudoku的方法
    ?
    ??? 2008年最后一篇,自然要來一點重量級內容,這篇摘錄了論壇里newkid大牛寫的解sudoku的PLSQL程序,特別值得推薦的就是分三種思想分別求解,以及PLSQL里數組的應用,基本上在平常的工作中很難用到,所以很有學習的價值。原文的地址如下:
    ???
    ??? http://www.itpub.net/viewthread.php?tid=1074409&extra=page%3D1%26amp%3Bfilter%3Ddigest
    ?

    1、sudoku_tests.sql
    ?
    ??? <摘錄了160個sudoku的題目,以及測試代碼,對程序進行檢測>

    CREATE TABLE sudoku_tests (
    ?????? id????????? NUMBER
    ????? ,cells?????? VARCHAR2(81)
    ????? ,used_time1? NUMBER(10,3)
    ????? ,used_time2? NUMBER(10,3)
    ????? ,used_time3? NUMBER(10,3)
    ????? );
    ?
    ---- 從這里下載的160個題目: http://www.sudokufans.org.cn/shudo/download/160hard.rar
    ?
    INSERT INTO sudoku_tests(id,cells) VALUES(1? ,'016400000200009000400000062070230100100000003003087040960000005000800007000006820');
    INSERT INTO sudoku_tests(id,cells) VALUES(2? ,'049008605003007000000000030000400800060815020001009000010000000000600400804500390');
    INSERT INTO sudoku_tests(id,cells) VALUES(3? ,'760500000000060008000000403200400800080000030005001007809000000600010000000003041');
    INSERT INTO sudoku_tests(id,cells) VALUES(4? ,'000605000003020800045090270500000001062000540400000007098060450006040700000203000');
    INSERT INTO sudoku_tests(id,cells) VALUES(5? ,'409000705000010000006207800200000009003704200800000004002801500000060000905000406');
    INSERT INTO sudoku_tests(id,cells) VALUES(6? ,'000010030040070501002008006680000003000302000300000045200500800801040020090020000');
    INSERT INTO sudoku_tests(id,cells) VALUES(7? ,'080070030260050018000000400000602000390010086000709000004000800810040052050090070');
    INSERT INTO sudoku_tests(id,cells) VALUES(8? ,'000093006000800900020006100000080053006000200370050000002500040001009000700130000');
    INSERT INTO sudoku_tests(id,cells) VALUES(9? ,'096500780007001000000000100604009070010802060080400203008000000000900300041008920');
    INSERT INTO sudoku_tests(id,cells) VALUES(10 ,'000000000140070000005106900021005080400000007080700620009304500000020018000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(11 ,'000600000047100000890040013001004020200090008030800500450070036000006840000005000');
    INSERT INTO sudoku_tests(id,cells) VALUES(12 ,'003070900000901000200308007072000510400000002015000840900104005000503000006020300');
    INSERT INTO sudoku_tests(id,cells) VALUES(13 ,'907002800300004057100070000009003000000020000000600200000010008570300004002700905');
    INSERT INTO sudoku_tests(id,cells) VALUES(14 ,'600000450080002000009070100000003940000040000012800000001080700000200030097000006');
    INSERT INTO sudoku_tests(id,cells) VALUES(15 ,'600000008000000100001307000004900280003102900092005300000203400005000000100000006');
    INSERT INTO sudoku_tests(id,cells) VALUES(16 ,'100000008050000070702000406900801007060000090010020050003080600080000040070503080');
    INSERT INTO sudoku_tests(id,cells) VALUES(17 ,'004705900000801000600040005430000082008000400920000063200030001000502000007608200');
    INSERT INTO sudoku_tests(id,cells) VALUES(18 ,'080306040100020008000050000300000006067080950800000002000070000600010003070904080');
    INSERT INTO sudoku_tests(id,cells) VALUES(19 ,'000000600004500097002800010070003001000050000200900080020006300130004700009000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(20 ,'000000009000020003046900050310200090000105000080009017030008420900030000100000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(21 ,'006300200708000000100050080400005030070010020090400008050040009000000506004006300');
    INSERT INTO sudoku_tests(id,cells) VALUES(22 ,'290700000004020010003004000050070060900203007020090030000500400010080600000006071');
    INSERT INTO sudoku_tests(id,cells) VALUES(23 ,'000000000500010004030605210090020081007000400260030050026803070900050008000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(24 ,'000000060005007009079080310130600000000000000000004078083050790900400600020000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(25 ,'000509000007000305000008170001900006020030010600004500084200000509000400000703000');
    INSERT INTO sudoku_tests(id,cells) VALUES(26 ,'309000000000030050041600000400700003080020040100004009000008120030050000000000906');
    INSERT INTO sudoku_tests(id,cells) VALUES(27 ,'000604002000039050008000400900003041003000500670100009002000100080490000700306000');
    INSERT INTO sudoku_tests(id,cells) VALUES(28 ,'000000007040800095005031000400003020006010800030200009000420700190006040600000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(29 ,'500904008001000070000007090007000400906805702003000600080100000060000900700406005');
    INSERT INTO sudoku_tests(id,cells) VALUES(30 ,'003600507000930000080007000058000000106000908000000340000400090000058000507009200');
    INSERT INTO sudoku_tests(id,cells) VALUES(31 ,'005000600004306900800209005040010080000000000002605700000000000006507300010000040');
    INSERT INTO sudoku_tests(id,cells) VALUES(32 ,'060000010790010032008000400000849000040607050000153000009000700670030091050000060');
    INSERT INTO sudoku_tests(id,cells) VALUES(33 ,'008009061010500009700030400090300008005000200800005030004020006300004070920800100');
    INSERT INTO sudoku_tests(id,cells) VALUES(34 ,'800000209000100007005002000060050004004080700300090020000900600200005000607000003');
    INSERT INTO sudoku_tests(id,cells) VALUES(35 ,'090008370000000000300605012000010006031060820200040000940201008000000000017400060');
    INSERT INTO sudoku_tests(id,cells) VALUES(36 ,'100260009070000050000008200003070004900846003800030600004600300080000040700081002');
    INSERT INTO sudoku_tests(id,cells) VALUES(37 ,'007006000004000006060109080006270000080000030000038900010802090500000800000300100');
    INSERT INTO sudoku_tests(id,cells) VALUES(38 ,'002000900090070030004000700028107650000050000007304100060000080001438200000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(39 ,'060000800000040500500200047008009060070105090030800100840006003002070000003000010');
    INSERT INTO sudoku_tests(id,cells) VALUES(40 ,'008000100070040030600507004007080600040602050006050300700205003020070080009000200');
    INSERT INTO sudoku_tests(id,cells) VALUES(41 ,'000009360010020000004000002003102006050070040100406900900000500000060030028700000');
    INSERT INTO sudoku_tests(id,cells) VALUES(42 ,'003004000602300000050600807508000009000070000700000201407008020000005904000700600');
    INSERT INTO sudoku_tests(id,cells) VALUES(43 ,'050901060700050003006000900800020004070403020400060005001000700600010008030504010');
    INSERT INTO sudoku_tests(id,cells) VALUES(44 ,'000300007806012000004005200000030050508000406040070000003800600000940301100003000');
    INSERT INTO sudoku_tests(id,cells) VALUES(45 ,'200070004006000800090308050003109600800000005001507300040803090002000400600040007');
    INSERT INTO sudoku_tests(id,cells) VALUES(46 ,'005000700020503080800090005030050070008704100070030040100040009040902010009000600');
    INSERT INTO sudoku_tests(id,cells) VALUES(47 ,'600801003080402010000090000890000052004000900510000037000010000030904020700603008');
    INSERT INTO sudoku_tests(id,cells) VALUES(48 ,'500003007001070000000805160208000500010090040005000709026709300000010900800200001');
    INSERT INTO sudoku_tests(id,cells) VALUES(49 ,'006908200030050080800000004400501003050000040200804007300000005060080010005107600');
    INSERT INTO sudoku_tests(id,cells) VALUES(50 ,'080063001400500030000004800060000902500000006207000080004600000090005003300720010');
    INSERT INTO sudoku_tests(id,cells) VALUES(51 ,'000002900050900800008001037060130208000804000803056090610400300004008070007600000');
    INSERT INTO sudoku_tests(id,cells) VALUES(52 ,'003000200014000390080000040030807050009040700007206800300000004000529000090070010');
    INSERT INTO sudoku_tests(id,cells) VALUES(53 ,'300104008008090100040000070200708004060000010700903005020000090001080400400309001');
    INSERT INTO sudoku_tests(id,cells) VALUES(54 ,'100703009002010600000406000380000064650000023720000058000508000008070200900602001');
    INSERT INTO sudoku_tests(id,cells) VALUES(55 ,'008102050020050800003000000070380500000209000009015060000000200005090010040508700');
    INSERT INTO sudoku_tests(id,cells) VALUES(56 ,'200010009000904000007805600045000920300000008079000140008109300000503000900040006');
    INSERT INTO sudoku_tests(id,cells) VALUES(57 ,'300000004020805090007090600060050010008704300070080020001020500080109040700000001');
    INSERT INTO sudoku_tests(id,cells) VALUES(58 ,'570904023800000004003000100300060005000401000100070002002000900700000001680502047');
    INSERT INTO sudoku_tests(id,cells) VALUES(59 ,'802000000300600500000050070080590040009000600060071090070020000001008007000000803');
    INSERT INTO sudoku_tests(id,cells) VALUES(60 ,'006020079000000001005630000003470000020009705000005400900008104600090000087000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(61 ,'070000060040507090009108300000802000010000020002903500200030004400206009005000600');
    INSERT INTO sudoku_tests(id,cells) VALUES(62 ,'010050080500603007006000500070060090600204001020030040002000400700106003080020060');
    INSERT INTO sudoku_tests(id,cells) VALUES(63 ,'060040050100000008008703600002107900800000002009502100001304200900000003030070090');
    INSERT INTO sudoku_tests(id,cells) VALUES(64 ,'080003900060400015300010600700000050002070800040000009001020503450006090006100070');
    INSERT INTO sudoku_tests(id,cells) VALUES(65 ,'010502080408000501090000030600050003000907000500010009050000040104000208030408070');
    INSERT INTO sudoku_tests(id,cells) VALUES(66 ,'130607092700201003000030000320000061005000300910000057000010000500403008270508036');
    INSERT INTO sudoku_tests(id,cells) VALUES(67 ,'800204007009030800070000090700106002060000070900402006090000050004060700300809004');
    INSERT INTO sudoku_tests(id,cells) VALUES(68 ,'800203005040050010003000800200506001060000030900708006006000100090020040100304007');
    INSERT INTO sudoku_tests(id,cells) VALUES(69 ,'090000020003908700500702009370040061006000900140070083900605008005107600010000050');
    INSERT INTO sudoku_tests(id,cells) VALUES(70 ,'730080016800609003000000000050407090200000004010502070000000000500104002370020045');
    INSERT INTO sudoku_tests(id,cells) VALUES(71 ,'000600000810400900040010030001300500030060020002007600070030090005009068000005000');
    INSERT INTO sudoku_tests(id,cells) VALUES(72 ,'032000590000000000007569300008706400004803700020000080080194060060070010000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(73 ,'020901040900702003000050000240000089009000400380000067000080000400207006050103070');
    INSERT INTO sudoku_tests(id,cells) VALUES(74 ,'000000000034105720016000450040080010009070200070000060700802006068090540000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(75 ,'059060340000000000100703006608000902700080001030000080000000000400207003007809100');
    INSERT INTO sudoku_tests(id,cells) VALUES(76 ,'406905803100030006093000750050000080800000002000894000620000037000000000001709600');
    INSERT INTO sudoku_tests(id,cells) VALUES(77 ,'009806300000040000400507009903000602010000080508000901700104006000060000001908200');
    INSERT INTO sudoku_tests(id,cells) VALUES(78 ,'700104008009000600030020010800701005002000100300402009020040090007000300100203006');
    INSERT INTO sudoku_tests(id,cells) VALUES(79 ,'006700084040005600000090000000030005930000021100050000000070000002400010780009300');
    INSERT INTO sudoku_tests(id,cells) VALUES(80 ,'008000090000095600010070300003000009046020710700000400002080030005940000060000200');
    INSERT INTO sudoku_tests(id,cells) VALUES(81 ,'091050800500704006000100000020000900100060003006000050000007000600803004009040270');
    INSERT INTO sudoku_tests(id,cells) VALUES(82 ,'007000500020000090034105670006408100000050000005703200063209410010000020002000300');
    INSERT INTO sudoku_tests(id,cells) VALUES(83 ,'060040030300000008001307500005080700700651002006070300003709100200000003050030090');
    INSERT INTO sudoku_tests(id,cells) VALUES(84 ,'120000006000090070000045100900506000006010500000207001007450000080020000400000089');
    INSERT INTO sudoku_tests(id,cells) VALUES(85 ,'200040608005060000000009010080700900300000002009004080070300000000050700803020005');
    INSERT INTO sudoku_tests(id,cells) VALUES(86 ,'400020003050801070007090500060000010501000307030000090005040100090608050200010006');
    INSERT INTO sudoku_tests(id,cells) VALUES(87 ,'200805009004000800060010020400203008005000100700901003090020060003000700600504001');
    INSERT INTO sudoku_tests(id,cells) VALUES(88 ,'040900100000008060690000002009003004050020070200100600700000089020800000004002050');
    INSERT INTO sudoku_tests(id,cells) VALUES(89 ,'042001000800000009000630000009007100650000082001200400000064000200000003000100560');
    INSERT INTO sudoku_tests(id,cells) VALUES(90 ,'080401090900050001001296400705000906069000320802000107007945800400010009090602010');
    INSERT INTO sudoku_tests(id,cells) VALUES(91 ,'005003020700050300010004805201000000070030010000000709809200640002060008060800100');
    INSERT INTO sudoku_tests(id,cells) VALUES(92 ,'010607050700000001004000800300010007000502000900070004006000100200000009070405060');
    INSERT INTO sudoku_tests(id,cells) VALUES(93 ,'600500002019080000070000040040100870000070000057003020020000050000090180800006004');
    INSERT INTO sudoku_tests(id,cells) VALUES(94 ,'020008000907030100050200930005300004070060010200009500042003070008050301000800020');
    INSERT INTO sudoku_tests(id,cells) VALUES(95 ,'560030900200090501000700000005008006070000080400900700000003000902040003006010054');
    INSERT INTO sudoku_tests(id,cells) VALUES(96 ,'003708600000020000200509007107000508020000090904000206600802001000040000008601700');
    INSERT INTO sudoku_tests(id,cells) VALUES(97 ,'780000021900501003003000400030904010000000000090807060001000900800209005560000042');
    INSERT INTO sudoku_tests(id,cells) VALUES(98 ,'300005006400270000008009000590300000700060009000004017000800600000012008800700004');
    INSERT INTO sudoku_tests(id,cells) VALUES(99 ,'600050001090301040007000200030104050100000002080705010001000600070906020500030008');
    INSERT INTO sudoku_tests(id,cells) VALUES(100,'830000000000400010100053200060200400007080100008009060006810004090005000000000021');
    INSERT INTO sudoku_tests(id,cells) VALUES(101,'000000700090500080007009600010090024020070060580060010004200900060008050005000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(102,'000000602000003040000480390014800000500030001000002730087041000090300000601000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(103,'300000009206030704070904080000040000000308000060109020050000090608000502012000670');
    INSERT INTO sudoku_tests(id,cells) VALUES(104,'100207006000906000004010200810000073005020400430000025001070800000802000500103004');
    INSERT INTO sudoku_tests(id,cells) VALUES(105,'500208006003010200010000080600904001020000040400701002080000030001050900900603007');
    INSERT INTO sudoku_tests(id,cells) VALUES(106,'005040790000007006800010002000800010901000203020001000400050007200300000069070500');
    INSERT INTO sudoku_tests(id,cells) VALUES(107,'012000004700600900905003080050430100000805000008016050090300805001007003500000640');
    INSERT INTO sudoku_tests(id,cells) VALUES(108,'600003507000020080003900006009700001010000030200006400100004200090080000302500008');
    INSERT INTO sudoku_tests(id,cells) VALUES(109,'070000030081903500006070000000100003800020009400006000000060400004508160020000080');
    INSERT INTO sudoku_tests(id,cells) VALUES(110,'060010502020008000400500008094002006000000000800300970600001007000600040509040080');
    INSERT INTO sudoku_tests(id,cells) VALUES(111,'020507030900203008000010000860401023007000800530809046000090000400605009090102050');
    INSERT INTO sudoku_tests(id,cells) VALUES(112,'000700000690040000042005000100200500020000090004009006008900100460050720070002030');
    INSERT INTO sudoku_tests(id,cells) VALUES(113,'040301080200000003005020100700106005004000200600402009009010700500000008030908020');
    INSERT INTO sudoku_tests(id,cells) VALUES(114,'061000200050901006000000080005060000040208060000030700020000000900604030008000470');
    INSERT INTO sudoku_tests(id,cells) VALUES(115,'004803200000705000300020008480000061007000500690000032200090007000407000008602300');
    INSERT INTO sudoku_tests(id,cells) VALUES(116,'310000057450687031000030000700204006003000500200803009000020000620548073580000062');
    INSERT INTO sudoku_tests(id,cells) VALUES(117,'000073000000245000072100300360000900005000800004000053009006120000421000000350000');
    INSERT INTO sudoku_tests(id,cells) VALUES(118,'001080500000109000400205001037000650500000002049000170900507006000402000005060900');
    INSERT INTO sudoku_tests(id,cells) VALUES(119,'300800710001027004080000002800004090030010070070900003200000040500460300047002005');
    INSERT INTO sudoku_tests(id,cells) VALUES(120,'008020000017503000450001600030005140800000009041700060004600035000304290000090400');
    INSERT INTO sudoku_tests(id,cells) VALUES(121,'036708000150400000807050000360000002008000100400000079000070905000005048000609310');
    INSERT INTO sudoku_tests(id,cells) VALUES(122,'200103009009000800070080040100020006007604200600090001060030050004000600900207004');
    INSERT INTO sudoku_tests(id,cells) VALUES(123,'500904001090307060001050900200000006900786005060102070100000002029000640000000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(124,'830701056690050027000000000200080004010405030400010009000000000520070068380206095');
    INSERT INTO sudoku_tests(id,cells) VALUES(125,'000000008020106000001080530700000400040307090005000001053010600000609070900000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(126,'000300000000060210016904080001000350020000060038000900050801420087030000000006000');
    INSERT INTO sudoku_tests(id,cells) VALUES(127,'090000010200608007007000500010070040000905000050020030001000300600209004040000050');
    INSERT INTO sudoku_tests(id,cells) VALUES(128,'800030005000204000007809100091000650500000003032000890004907500000502000900060007');
    INSERT INTO sudoku_tests(id,cells) VALUES(129,'300040009009000100050906030005704900400000002003501700040803020006000300500060008');
    INSERT INTO sudoku_tests(id,cells) VALUES(130,'600903004009600100030000000200490060004050300070032005000000010007009600300805002');
    INSERT INTO sudoku_tests(id,cells) VALUES(131,'807001500030980000400300002058100006060000050900003280500006001000059040002800605');
    INSERT INTO sudoku_tests(id,cells) VALUES(132,'090080020000947000000203000027406980100000005006105700005000800410000039800000004');
    INSERT INTO sudoku_tests(id,cells) VALUES(133,'000005000009610040300070002000400310004000500085007000800020009070098400000100000');
    INSERT INTO sudoku_tests(id,cells) VALUES(134,'000000000007020800863000152600809004030000010004000200090308020040507090006000400');
    INSERT INTO sudoku_tests(id,cells) VALUES(135,'006040002040001000800006000000105970002000500073804000000300004000500010900070200');
    INSERT INTO sudoku_tests(id,cells) VALUES(136,'001090700300507004050462030000308000043000510000601000010935020200106005008070300');
    INSERT INTO sudoku_tests(id,cells) VALUES(137,'005006300000410900700000065030092001060103080800640030270000003009038000003900400');
    INSERT INTO sudoku_tests(id,cells) VALUES(138,'000720100100805003000000040400010006070000020500090004050000000600104007004063000');
    INSERT INTO sudoku_tests(id,cells) VALUES(139,'000105000400000001302000508040000070600010004900000002000050000050708060007634800');
    INSERT INTO sudoku_tests(id,cells) VALUES(140,'005200800070030090900400002000000609050010040809000000200003004010040060008001900');
    INSERT INTO sudoku_tests(id,cells) VALUES(141,'005080000070309000900000304480600000000050000000007031604000002000802070000030500');
    INSERT INTO sudoku_tests(id,cells) VALUES(142,'008000100100267003020080070060509010009000300030402060080040050500826001003000800');
    INSERT INTO sudoku_tests(id,cells) VALUES(143,'230000060600009708000605010003700690000000000097004800020106000804200006010000029');
    INSERT INTO sudoku_tests(id,cells) VALUES(144,'920035100050000000008690000804500020000000000010004908000029700000000060005460092');
    INSERT INTO sudoku_tests(id,cells) VALUES(145,'003000000090040020005701006004010600010408090008020700800209000050080010000000400');
    INSERT INTO sudoku_tests(id,cells) VALUES(146,'005302004000000500020600008100005000030981060000200009400006010008000000300508400');
    INSERT INTO sudoku_tests(id,cells) VALUES(147,'600807001010326070000104000146000859030000010759000243000409000060513020300208005');
    INSERT INTO sudoku_tests(id,cells) VALUES(148,'001050200050107080200309005013000920900000004024000650100804002070205010002060500');
    INSERT INTO sudoku_tests(id,cells) VALUES(149,'070080000100420900008301070017000500850000031009000280090604800003018005000030060');
    INSERT INTO sudoku_tests(id,cells) VALUES(150,'270040081500800007000000300000308090700050002060204000006000900300005004940030015');
    INSERT INTO sudoku_tests(id,cells) VALUES(151,'040310002203006000060809000802000540600000007059000206000608020000100605100092030');
    INSERT INTO sudoku_tests(id,cells) VALUES(152,'000000370009750001080103000040300100000080000007006050000208090800014700092000000');
    INSERT INTO sudoku_tests(id,cells) VALUES(153,'530004600100070900002000074000030001060807040700060000250000100009010006004700052');
    INSERT INTO sudoku_tests(id,cells) VALUES(154,'003060700000800020500207004071040600800609007002080490100508006020006000008070900');
    INSERT INTO sudoku_tests(id,cells) VALUES(155,'010070600000000090030006500006150040300080002070093100002900080060000000008020010');
    INSERT INTO sudoku_tests(id,cells) VALUES(156,'020000080600080003000704000007106400010090070004203900000305000800060001060000090');
    INSERT INTO sudoku_tests(id,cells) VALUES(157,'000007090940000002002800076000070600500010008004060000710005800300000054050900000');
    INSERT INTO sudoku_tests(id,cells) VALUES(158,'000709000750000039009302500405090302000000000201060904003801700620000013000607000');
    INSERT INTO sudoku_tests(id,cells) VALUES(159,'500084000010500004060000800900030000080706090000020001002000060700009080000240003');
    INSERT INTO sudoku_tests(id,cells) VALUES(160,'009080005517000000000061700190030500003008604000000000060070049402003060070006050');
    ?
    ----- 測試腳本
    SET SERVEROUTPUT ON;
    ?
    DECLARE
    ?? v_start_time NUMBER;
    BEGIN
    ?? update sudoku_tests set used_time1 = NULL;
    ?? FOR lv_rec IN (SELECT * FROM sudoku_tests) LOOP
    ?????? v_start_time := dbms_utility.get_time;
    ?????? sudoku(lv_rec.cells);
    ?????? update sudoku_tests set used_time1 = dbms_utility.get_time - v_start_time where id = lv_rec.id;
    ?? END LOOP;
    ?? COMMIT;
    END;
    /
    ?
    SELECT MAX(USED_TIME1)/100,MIN(USED_TIME1)/100,AVG(USED_TIME1)/100 FROM SUDOKU_TESTS;
    ?
    ?
    2、sudoku.sql
    ?
    ??? <本例中所用到的思路十分樸素,之所以效果不錯,要得益于一系列標志位的設計,它們能夠快速判斷一個數字是否被用過。我注意到了對空單元格遍歷順序的改變能夠影響整個解題效率,那么在進入主循環之前能否找到一種最為高效的遍歷順序呢?或者順序根本就應該是動態的,根據取值進行調整?我作了幾個猜想都不成功,目前用的還是行,列的自然順序。希望對此有研究的朋友多多賜教,大家都把自己的算法貼出來,或者互相吹捧或者互相抬杠,樂在其中>
    ?
    CREATE OR REPLACE TYPE t_num IS TABLE OF NUMBER
    /
    ?
    CREATE OR REPLACE TYPE type_slot AS OBJECT? (
    ??????????? r?????????? NUMBER
    ?????????? ,c?????????? NUMBER
    ?????????? ,cnt???????? NUMBER
    ?????????? ,idx???????? NUMBER
    ? )
    /
    ?
    CREATE OR REPLACE TYPE table_slot AS TABLE OF type_slot
    /
    ?

    CREATE OR REPLACE PROCEDURE sudoku (p_str IN VARCHAR2 DEFAULT NULL)
    AS
    ?? TYPE t2_num IS TABLE OF t_num INDEX BY BINARY_INTEGER;
    ?? TYPE t3_num IS TABLE OF t2_num INDEX BY BINARY_INTEGER;
    ?? TYPE t_str IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
    ?
    ?? s t_str;????? ---- 字符串數組,存放題目
    ?
    ?? ------ 三組標志位用于快速判斷某數字是否可以用于填充
    ?? used_c t2_num;???? --- 在此列中該數字是否已被使用
    ?? used_r t2_num;???? --- 在此行中該數字是否已被使用
    ?? used_a t2_num;???? --- 在此區中該數字是否已被使用(從上至下,從左到右劃分為9個區)
    ?
    ?? area?? t2_num;???? --- 根據行,列迅速返回所屬的區
    ?
    ??
    ?? slot_values t3_num;? --- 為每個單元格存放候選數字。每個坐標對應一系列標志位,如果slot_values(i)(j)(k)有值則k為i行j列的候選值
    ??????????????????????? --- 只對空單元有意義
    ??
    ?? v_idx? NUMBER;?????? -- 用于遍歷空單元格的指針變量
    ?
    ?? i? NUMBER;?????????? --- 臨時變量
    ?? j? NUMBER;
    ?? k? NUMBER;
    ?
    ?? empty_set? t_num := t_num(0,0,0,0,0,0,0,0,0);
    ?
    ?? empty_slots table_slot := table_slot();????? --- 存放空單元格,此數組中每個元素表示一個坐標, 以及一個指向候選值數組的指針。根據坐標及指針可到slot_values取候選值
    ?
    ?? v_continue NUMBER;
    ?? v_del????? NUMBER;
    ?
    BEGIN
    ?? --- sample one
    ?? s(1):= '3 58? 176';
    ?? s(2):= '1?? 5?? 2';
    ?? s(3):= '????? 549';
    ?? s(4):= ' 52 986? ';
    ?? s(5):= '43? 12? 7';
    ?? s(6):= '?? 5? 4? ';
    ?? s(7):= '5?? 6 894';
    ?? s(8):= ' 69 7?? 5';
    ?? s(9):= '?? 9?? 61';
    ?
    ?? ---- junsansi's sample
    ?? s(1):= '7? 25? 98' ;
    ?? s(2):= '? 6??? 1 ' ;
    ?? s(3):= '?? 61 3? ' ;
    ?? s(4):= '9??? 1?? ' ;
    ?? s(5):= '??? 8 4 9' ;
    ?? s(6):= '? 75 28 1' ;
    ?? s(7):= ' 94? 3?? ' ;
    ?? s(8):= '??? 4923 ' ;
    ?? s(9):= '61???? 4 ' ;
    ?
    ?? --- AlEscargot, the most complex SUDOKU puzzle ever
    ?? s(1):= '1??? 7 9 ' ;
    ?? s(2):= ' 3? 2?? 8' ;
    ?? s(3):= '? 96? 5? ' ;
    ?? s(4):= '? 53? 9? ' ;
    ?? s(5):= ' 1? 8?? 2' ;
    ?? s(6):= '6??? 4?? ' ;
    ?? s(7):= '3????? 1 ' ;
    ?? s(8):= ' 4????? 7' ;
    ?? s(9):= '? 7?? 3? ' ;
    ?
    ?? FOR i IN 1..9 LOOP
    ?????? IF p_str IS NOT NULL THEN
    ????????? s(i):= SUBSTR(p_str,(i-1)*9+1,9);
    ?????? END IF;
    ?????? used_r(i) := empty_set;??????????? ----- 初始化為未使用狀態
    ?????? used_c(i) := empty_set;
    ?????? used_a(i) := empty_set;
    ?????? area(i)?? := empty_set;??????????? ----- 初始化, 真正填值在下面
    ?
    ?????? FOR j IN 1..9 LOOP
    ?????????? area(i)(j) := (CEIL(i/3)-1)*3 + CEIL(j/3);??? -- 行列和區域的換算關系
    ?????????? slot_values(i)(j) := empty_set;?????????????? -- 為每個坐標賦予完整的候選數字清單
    ?????? END LOOP;
    ?? END LOOP;
    ?
    ?? FOR i IN 1..9 LOOP
    ?????? FOR j IN 1..9 LOOP
    ?????????? IF SUBSTR(s(i),j,1) BETWEEN '1' AND '9' THEN
    ????????????? k := TO_NUMBER(SUBSTR(s(i),j,1));
    ????????????? used_r(i)(k) :=1;
    ????????????? used_c(j)(k) :=1;
    ????????????? used_a(area(i)(j))(k) :=1;
    ?
    ????????????? FOR v_del IN 1..9 LOOP?????? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除。slot_values將成為稀疏數組
    ????????????????? slot_values(i)(v_del).DELETE(k);??
    ????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????? END LOOP;
    ?
    ?????????? ELSE
    ????????????? ------ 發現一個未填的空單元
    ????????????? empty_slots.EXTEND;
    ????????????? empty_slots(empty_slots.COUNT) := type_slot(i,j,0,0);
    ?????????? END IF;
    ?????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue :=1;
    ?? WHILE v_continue = 1 AND empty_slots.COUNT>0 LOOP
    ???????? ---- 對空單元進行篩選,如果只有一個候選數字則視為已知答案,從空單元清單中刪除
    ???????? v_continue := 0;
    ???????? v_idx := empty_slots.FIRST;
    ???????? WHILE v_idx IS NOT NULL LOOP
    ?????????????? empty_slots(v_idx).cnt := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).COUNT;? --- 這句已經沒有意義了,本來是想用它排序的但效果不好
    ?????????????? IF empty_slots(v_idx).cnt = 0 THEN
    ????????????????? RAISE_APPLICATION_ERROR(-20001,'invalid sudoku at '||empty_slots(v_idx).r||','||empty_slots(v_idx).c);
    ?????????????? ELSIF empty_slots(v_idx).cnt = 1 THEN
    ????????????????? i := empty_slots(v_idx).r;
    ????????????????? j := empty_slots(v_idx).c;
    ????????????????? k := slot_values(i)(j).FIRST;
    ????????????????? used_r(i)(k) :=1;
    ????????????????? used_c(j)(k) :=1;
    ????????????????? used_a(area(i)(j))(k) :=1;
    ?
    ????????????????? FOR v_del IN 1..9 LOOP? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除
    ????????????????????? slot_values(i)(v_del).DELETE(k);
    ????????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????????? END LOOP;
    ?
    ????????????????? v_continue := 1;??? ---- 繼續循環,因為本次刪除可能導致產生新的已知單元格
    ????????????????? v_del := v_idx;???? ---- 本單元格已經非空,可以刪除
    ????????????????? s(i) := SUBSTR(s(i),1,j-1) ||k|| SUBSTR(s(i),j+1);
    ?????????????? ELSE
    ????????????????? v_del := 0;
    ?????????????? END IF;
    ?
    ?????????????? v_idx := empty_slots.NEXT(v_idx);? ----- 用鏈表方式進行遍歷,因為數組可能是稀疏的
    ?
    ?????????????? IF v_del>0 THEN
    ????????????????? empty_slots.DELETE(v_del);
    ?????????????? END IF;
    ?
    ???????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue := 1;
    ?
    ?? IF empty_slots.COUNT>0 THEN
    ?????
    ????? ----- 借鑒小表驅動大表的思路進行排序預處理。實際應用效果不佳,此SELECT可以去掉。
    ????? -- SELECT CAST(MULTISET(SELECT * FROM TABLE(CAST(empty_slots AS table_slot)) ORDER BY cnt,r,c) AS table_slot)
    ????? --?? INTO empty_slots
    ????? --?? FROM DUAL;
    ?
    ????? v_idx := empty_slots.FIRST;???? --- 取第一個空單元格
    ????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST;? ---- 取出此位置的第一個候選值
    ?
    ????? WHILE v_idx IS NOT NULL LOOP?? ---- 遍歷所有空單元格, 主循環(最為耗時)開始
    ??????????? WHILE empty_slots(v_idx).idx IS NOT NULL LOOP????? ---- 遍歷此位置所有候選值, 查找可用數字
    ????????????????? i := empty_slots(v_idx).r;
    ????????????????? j := empty_slots(v_idx).c;
    ????????????????? k := empty_slots(v_idx).idx;??? ---- 因為我采用位圖的數據結構,位置即候選值。slot_values(i)(j)(k)存什么值無所謂,本例中恒為0
    ?
    ????????????????? IF used_c(j)(k) = 0 AND used_r(i)(k) = 0 AND used_a(area(i)(j))(k) = 0 THEN? ---- 這個值未用過
    ???????????????????? used_c(j)(k) := 1;
    ???????????????????? used_r(i)(k) := 1;
    ???????????????????? used_a(area(i)(j))(k) :=1;
    ???????????????????? EXIT;??? ---- 找到一個未用過的值,退出本循環,繼續下一個單元格
    ????????????????? ELSE
    ???????????????????? empty_slots(v_idx).idx := slot_values(i)(j).NEXT(empty_slots(v_idx).idx);? -- 用鏈表方式找下一個位置,因為數組可能是稀疏的
    ????????????????? END IF;
    ??????????? END LOOP;
    ?
    ??????????? IF empty_slots(v_idx).idx IS NULL THEN?? ---- 指針到了末尾,所有值都不可用,必須退回到上一單元格
    ?
    ?????????????? v_idx := empty_slots.PRIOR(v_idx);???? --- 退回到上一單元格
    ?????????????? IF v_idx IS NULL THEN????? ----- 無處可退,此題沒有答案
    ????????????????? v_continue := 0;
    ????????????????? EXIT;
    ?????????????? END IF;
    ?
    ?????????????? i := empty_slots(v_idx).r;????? ----- 回到上一單元格,當前值證明不行,必須釋放它并置為未用
    ?????????????? j := empty_slots(v_idx).c;
    ?????????????? k := empty_slots(v_idx).idx;
    ?
    ?????????????? used_c(j)(k) := 0;
    ?????????????? used_r(i)(k) := 0;
    ?????????????? used_a(area(i)(j))(k) :=0;
    ?
    ?????????????? empty_slots(v_idx).idx := slot_values(i)(j).NEXT(empty_slots(v_idx).idx);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?
    ??????????? ELSE
    ???????????? ---- 找到一個未用過的值,繼續下一個空單元格
    ?????????????? v_idx := empty_slots.NEXT(v_idx);
    ?
    ?????????????? IF v_idx IS NULL THEN????? ----- 所有空單元格都已處理完,答案找到了
    ????????????????? EXIT;
    ?????????????? END IF;
    ?????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST; ---- 取出此位置的第一個候選值
    ??????????? END IF;
    ????? END LOOP;
    ?
    ?? END IF;
    ?
    ?? IF v_continue = 1 THEN
    ????? v_idx := empty_slots.FIRST;
    ?
    ????? WHILE v_idx IS NOT NULL LOOP?????????? --取出空單元格里面填好的值,拼回字符串
    ??????????? i := empty_slots(v_idx).r;
    ??????????? j := empty_slots(v_idx).c;
    ??????????? k := empty_slots(v_idx).idx;
    ??????????? s(i) := SUBSTR(s(i),1,j-1) || k || SUBSTR(s(i),j+1);
    ?
    ??????????? v_idx := empty_slots.NEXT(v_idx);
    ????? END LOOP;
    ?
    ????? DBMS_OUTPUT.PUT_LINE('Answer Found:');
    ????? FOR i IN 1..9 LOOP? ------ 輸出答案
    ????????? DBMS_OUTPUT.PUT_LINE(s(i));
    ????? END LOOP;
    ?? ELSE
    ????? DBMS_OUTPUT.PUT_LINE('No Answer Found!');
    ?
    ?? END IF;
    ?
    END sudoku;
    /
    ?
    ?
    3、sudoku2.sql
    ?
    ??? <這里是我的另一種嘗試,在進入主循環之前對所有空位排序。排序的原則是從最薄弱的環節開始擊破,即查找那些行、列、區中空位最少的單元。除此之外和原來的算法一樣。我到老地方下載了“高手進階”的五萬個題目,只對其中1000個進行了測試并和上一種解法作比較。一千個做下來平均0.27秒,最壞的情況是5.6秒;舊方法平均是1.15秒,最壞情況54.38秒。可見新算法有所改進。但其中也有約三分之一是舊算法更快,盡管差距不大。我在新代碼中有意使用了VARRAY, 這下子三種COLLECTION都用上了,顯得很花哨,也可當作COLLECTION應用的范例來看>
    ?
    CREATE GLOBAL TEMPORARY TABLE sudoku_slots (
    ??????????? r?????????? NUMBER
    ?????????? ,c?????????? NUMBER?????
    ?????????? ,a?????????? NUMBER?????
    ?????????? ,cnt???????? NUMBER
    ?????????? ,idx???????? NUMBER
    ?????????? ,sort_order? NUMBER
    ? ) ON COMMIT PRESERVE ROWS
    /
    ?
    CREATE OR REPLACE PROCEDURE sudoku2(p_str IN VARCHAR2 DEFAULT NULL)
    AS
    ?? TYPE t_num IS TABLE OF NUMBER;
    ?
    ?? TYPE t2_num IS VARRAY(9) OF t_num;
    ?? TYPE t3_num IS VARRAY(9) OF t2_num;
    ??
    ?? TYPE t_str IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
    ?
    ?? s t_str;????? ---- 字符串數組,存放題目
    ?
    ?? ------ 三組標志位用于快速判斷某數字是否可以用于填充
    ?? used_c t2_num := t2_num();???? --- 在此列中該數字是否已被使用
    ?? used_r t2_num := t2_num();???? --- 在此列中該數字是否已被使用
    ?? used_a t2_num := t2_num();???? --- 在此區中該數字是否已被使用(從上至下,從左到右劃分為9個區)
    ?
    ?? area?? t2_num := t2_num();???? --- 根據行,列迅速返回所屬的區
    ?
    ??
    ?? slot_values t3_num := t3_num();? --- 為每個單元格存放候選數字。每個坐標對應一系列標志位,如果slot_values(i)(j)(k)有值則k為i行j列的候選值
    ??????????????????????? --- 只對空單元有意義
    ??
    ?? v_idx? NUMBER;?????? -- 用于遍歷空單元格的指針變量
    ?
    ?? i? NUMBER;?????????? --- 臨時變量
    ?? j? NUMBER;
    ?? k? NUMBER;
    ?
    ?? empty_set? t_num := t_num(0,0,0,0,0,0,0,0,0);
    ?
    ?? TYPE t_sudoku_slots IS TABLE OF sudoku_slots%ROWTYPE;
    ?? empty_slots t_sudoku_slots;??? --- 存放空單元格,此數組中每個元素表示一個坐標, 以及一個指向候選值數組的指針。根據坐標及指針可到slot_values取候選值
    ??
    ?? v_continue NUMBER;
    ?
    BEGIN
    ?
    /*
    ?? ---- junsansi's sample
    ?? s(1):= '7? 25? 98' ;
    ?? s(2):= '? 6??? 1 ' ;
    ?? s(3):= '?? 61 3? ' ;
    ?? s(4):= '9??? 1?? ' ;
    ?? s(5):= '??? 8 4 9' ;
    ?? s(6):= '? 75 28 1' ;
    ?? s(7):= ' 94? 3?? ' ;
    ?? s(8):= '??? 4923 ' ;
    ?? s(9):= '61???? 4 ' ;
    ?
    ?? --- sample one
    ?? s(1):= '3 58? 176';
    ?? s(2):= '1?? 5?? 2';
    ?? s(3):= '????? 549';
    ?? s(4):= ' 52 986? ';
    ?? s(5):= '43? 12? 7';
    ?? s(6):= '?? 5? 4? ';
    ?? s(7):= '5?? 6 894';
    ?? s(8):= ' 69 7?? 5';
    ?? s(9):= '?? 9?? 61';
    */
    ?
    ?? --- AlEscargot, the most complex SUDOKU puzzle ever
    ?? s(1):= '1??? 7 9 ' ;
    ?? s(2):= ' 3? 2?? 8' ;
    ?? s(3):= '? 96? 5? ' ;
    ?? s(4):= '? 53? 9? ' ;
    ?? s(5):= ' 1? 8?? 2' ;
    ?? s(6):= '6??? 4?? ' ;
    ?? s(7):= '3????? 1 ' ;
    ?? s(8):= ' 4????? 7' ;
    ?? s(9):= '? 7?? 3? ' ;
    ?

    ?? used_r.EXTEND(9);????? ----- 對VARRAY數組進行初始化
    ?? used_c.EXTEND(9);
    ?? used_a.EXTEND(9);
    ?? area.EXTEND(9);
    ?? slot_values.EXTEND(9);? ----- 對VARRAY數組(第一維)進行初始化
    ??
    ?? FOR i IN 1..9 LOOP
    ?????? IF p_str IS NOT NULL THEN
    ????????? s(i):= SUBSTR(p_str,(i-1)*9+1,9);
    ?????? END IF;
    ?????? used_r(i) := empty_set;??????????? ----- 初始化為未使用狀態
    ?????? used_c(i) := empty_set;
    ?????? used_a(i) := empty_set;
    ?
    ?????? area(i)?? := empty_set;??????????? ----- 初始化, 真正填值在下面
    ?
    ?????? slot_values(i) := t2_num();????? ----- 對VARRAY數組(第二維)進行初始化
    ?????? slot_values(i).EXTEND(9);
    ?????? FOR j IN 1..9 LOOP
    ?????????? area(i)(j) := (CEIL(i/3)-1)*3 + CEIL(j/3);??? -- 行列和區域的換算關系
    ?????????? slot_values(i)(j) := empty_set;?????????????? -- 為每個坐標賦予完整的候選數字清單
    ?????? END LOOP;
    ?? END LOOP;
    ??
    ?? DELETE sudoku_slots;
    ??
    ?? FOR i IN 1..9 LOOP
    ?????? FOR j IN 1..9 LOOP
    ?????????? IF SUBSTR(s(i),j,1) BETWEEN '1' AND '9' THEN
    ????????????? k := TO_NUMBER(SUBSTR(s(i),j,1));
    ????????????? used_r(i)(k) :=1;
    ????????????? used_c(j)(k) :=1;
    ????????????? used_a(area(i)(j))(k) :=1;
    ?????????????
    ????????????? FOR v_del IN 1..9 LOOP?????? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除。slot_values將成為稀疏數組
    ????????????????? slot_values(i)(v_del).DELETE(k);
    ????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????? END LOOP;
    ?
    ?????????? ELSE
    ????????????? ------ 發現一個未填的空單元
    ????????????? INSERT INTO sudoku_slots (r,c,a) VALUES (i,j,area(i)(j));
    ?
    ?????????? END IF;
    ?????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue :=1;
    ?? WHILE v_continue = 1 LOOP
    ???????? ---- 對空單元進行篩選,如果只有一個候選數字則視為已知答案,從空單元清單中刪除
    ?
    ???????? v_continue := 0;
    ????????
    ???????? FOR lv_rec IN (SELECT * FROM sudoku_slots) LOOP
    ???????????? v_idx := slot_values(lv_rec.r)(lv_rec.c).COUNT;
    ?????????????? IF v_idx = 0 THEN
    ????????????????? RAISE_APPLICATION_ERROR(-20001,'invalid sudoku at '||lv_rec.r||','||lv_rec.c);
    ?????????????? ELSIF v_idx = 1 THEN
    ????????????????? i := lv_rec.r;
    ????????????????? j := lv_rec.c;
    ????????????????? k := slot_values(i)(j).FIRST;
    ????????????????? used_r(i)(k) :=1;
    ????????????????? used_c(j)(k) :=1;
    ????????????????? used_a(area(i)(j))(k) :=1;
    ?????????????????
    ????????????????? FOR v_del IN 1..9 LOOP? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除
    ????????????????????? slot_values(i)(v_del).DELETE(k);
    ????????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????????? END LOOP;
    ?????????????????
    ????????????????? v_continue := 1;??? ---- 繼續循環,因為本次刪除可能導致產生新的已知單元格
    ????????????????? s(i) := SUBSTR(s(i),1,j-1) ||k|| SUBSTR(s(i),j+1);
    ?????????????????
    ????????????????? DELETE sudoku_slots WHERE r=lv_rec.r AND c=lv_rec.c; ---- 本單元格已經非空,可以刪除
    ?????????????? ELSE
    ????????????????? UPDATE sudoku_slots SET cnt = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ?????????????? END IF;
    ??????????????
    ???????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue := 1;
    ?
    ?? v_idx := 0;
    ?? ---- 對空單元格進行排序。排序原則是優先取所在的行、列、區空位最少的單元
    ?? WHILE v_continue >0 LOOP
    ???????? v_continue := 0;
    ?
    ???????? FOR lv_rec IN (SELECT r,c,a
    ????????????????????????????? ,LEAST(r_cnt,c_cnt,a_cnt) AS cnt1
    ????????????????????????????? ,r_cnt+c_cnt+a_cnt cnt2
    ????????????????????????????? ,cnt
    ???????????????????????? FROM (SELECT r,c,a,cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY r) AS r_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY c) AS c_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY a) AS a_cnt
    ???????????????????????????????? FROM sudoku_slots
    ??????????????????????????????? WHERE sort_order IS NULL
    ??????????????????????????????? )
    ??????????????????????? ORDER BY cnt1,cnt2,cnt
    ??????????????????????? )
    ???????? LOOP
    ???????????? v_idx := v_idx +1;
    ???????????? UPDATE sudoku_slots SET sort_order = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ???????????? v_continue := 1;
    ??
    ???????????? EXIT;
    ???????? END LOOP;
    ?
    ?? END LOOP;
    ?
    ?? ---- 把排好序的數據載入內存數組
    ?? SELECT *
    ???? BULK COLLECT INTO empty_slots
    ???? FROM sudoku_slots
    ???? ORDER BY sort_order;
    ?
    ?? v_continue := 1;
    ??
    ?? IF empty_slots.COUNT>0 THEN
    ?
    ????? v_idx := 1;???? --- 取第一個空單元格
    ????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST;? ---- 取出此位置的第一個候選值
    ?
    ????? WHILE v_idx <= empty_slots.COUNT LOOP?? ---- 遍歷所有空單元格, 主循環(最為耗時)開始
    ??????????? WHILE empty_slots(v_idx).idx IS NOT NULL LOOP????? ---- 遍歷此位置所有候選值, 查找可用數字
    ????????????????? i := empty_slots(v_idx).r;
    ????????????????? j := empty_slots(v_idx).c;
    ????????????????? k := empty_slots(v_idx).idx;??? ---- 因為我采用位圖的數據結構,位置即候選值。slot_values(i)(j)(k)存什么值無所謂,本例中恒為0
    ?
    ????????????????? IF used_c(j)(k) = 0 AND used_r(i)(k) = 0 AND used_a(area(i)(j))(k) = 0 THEN? ---- 這個值未用過
    ???????????????????? used_c(j)(k) := 1;
    ???????????????????? used_r(i)(k) := 1;
    ???????????????????? used_a(area(i)(j))(k) :=1;
    ???????????????????? EXIT;??? ---- 找到一個未用過的值,退出本循環,繼續下一個單元格
    ????????????????? ELSE
    ???????????????????? empty_slots(v_idx).idx := slot_values(i)(j).NEXT(empty_slots(v_idx).idx);? -- 用鏈表方式找下一個位置,因為數組可能是稀疏的
    ????????????????? END IF;
    ??????????? END LOOP;
    ?
    ??????????? IF empty_slots(v_idx).idx IS NULL THEN?? ---- 指針到了末尾,所有值都不可用,必須退回到上一單元格
    ?
    ?????????????? v_idx := v_idx-1;???? --- 退回到上一單元格
    ?????????????? IF v_idx =0 THEN????? ----- 無處可退,此題沒有答案
    ????????????????? v_continue := 0;
    ????????????????? EXIT;
    ?????????????? END IF;
    ?
    ?????????????? i := empty_slots(v_idx).r;????? ----- 回到上一單元格,當前值證明不行,必須釋放它并置為未用
    ?????????????? j := empty_slots(v_idx).c;
    ?????????????? k := empty_slots(v_idx).idx;
    ?
    ?????????????? used_c(j)(k) := 0;
    ?????????????? used_r(i)(k) := 0;
    ?????????????? used_a(area(i)(j))(k) :=0;
    ?
    ?????????????? empty_slots(v_idx).idx := slot_values(i)(j).NEXT(empty_slots(v_idx).idx);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?
    ??????????? ELSE
    ???????????? ---- 找到一個未用過的值,繼續下一個空單元格
    ?????????????? v_idx := v_idx+1;
    ?
    ?????????????? IF v_idx >empty_slots.COUNT THEN????? ----- 所有空單元格都已處理完,答案找到了
    ????????????????? EXIT;
    ?????????????? END IF;
    ?????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST; ---- 取出此位置的第一個候選值
    ??????????? END IF;
    ????? END LOOP;
    ?
    ?? END IF;
    ?
    ?? IF v_continue = 1 THEN
    ?
    ????? FOR v_idx IN 1..empty_slots.COUNT LOOP?????????? --取出空單元格里面填好的值,拼回字符串
    ??????????? i := empty_slots(v_idx).r;
    ??????????? j := empty_slots(v_idx).c;
    ??????????? k := empty_slots(v_idx).idx;
    ??????????? s(i) := SUBSTR(s(i),1,j-1) || k || SUBSTR(s(i),j+1);
    ?
    ????? END LOOP;
    ?
    ????? DBMS_OUTPUT.PUT_LINE('Answer Found:');
    ????? FOR i IN 1..9 LOOP? ------ 輸出答案
    ????????? DBMS_OUTPUT.PUT_LINE(s(i));
    ????? END LOOP;
    ?? ELSE
    ????? DBMS_OUTPUT.PUT_LINE('No Answer Found!');
    ?
    ?? END IF;
    ?
    END;
    /
    ?
    ?
    4、sudoku3.sql
    ?
    ??? <第三種嘗試:放棄前面用的標志位方法,為每個空位設置一個候選值數組。此方法的優勢是不需要判斷,有值就肯定是未用過的;代價就是每當用了一個值,必須從后續節點的候選值(可用值數組)刪除它。另一好處就是當要刪除時如果發現此值是唯一的,則可以快速斷定該值不可用。實際效果:1000個題目的平均用時從0.27減少為0.17秒>
    ?
    CREATE GLOBAL TEMPORARY TABLE sudoku_slots (
    ??????????? r?????????? NUMBER
    ?????????? ,c?????????? NUMBER?????
    ?????????? ,a?????????? NUMBER?????
    ?????????? ,cnt???????? NUMBER
    ?????????? ,idx???????? NUMBER
    ?????????? ,sort_order? NUMBER
    ? ) ON COMMIT PRESERVE ROWS
    /
    ?

    CREATE OR REPLACE PROCEDURE sudoku3(p_str IN VARCHAR2 DEFAULT NULL)
    AS
    ?? TYPE t_num IS TABLE OF NUMBER;
    ?
    ?? TYPE t2_num IS VARRAY(9) OF t_num;
    ?? TYPE t3_num IS VARRAY(9) OF t2_num;
    ??
    ?? TYPE t_str IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
    ?
    ?? s t_str;????? ---- 字符串數組,存放題目
    ?
    ??
    ?? slot_values t3_num := t3_num();? --- 為每個單元格存放候選數字。每個坐標對應一系列標志位,如果slot_values(i)(j)(k)有值則k為i行j列的候選值
    ??????????????????????? --- 只對空單元有意義
    ??
    ?? v_idx? NUMBER;?????? -- 用于遍歷空單元格的指針變量
    ?
    ?? i? NUMBER;?????????? --- 臨時變量
    ?? j? NUMBER;
    ?? k? NUMBER;
    ?
    ?? empty_set? t_num := t_num(0,0,0,0,0,0,0,0,0);
    ?
    ?? TYPE t_sudoku_slots IS TABLE OF sudoku_slots%ROWTYPE;
    ?? empty_slots t_sudoku_slots;??? --- 存放空單元格,此數組中每個元素表示一個坐標, 以及一個指向候選值數組的指針。根據坐標及指針可到slot_values取候選值
    ??
    ?? v_continue NUMBER;
    ?
    ?? deleted_by t3_num := t3_num(); ----如果某單元的某值被它的上級刪除,則這里存放著上級單元的編號
    ?
    ?? TYPE t_ptr IS TABLE OF t_sudoku_slots INDEX BY BINARY_INTEGER;
    ?
    ?? pointers t_ptr;????? --- 對應于empty_slots中的每個空單元格,這組指針指向其后續空位,而且和本節點是處于同一行或列或區的
    ??????????????????????? --- 當這個空位取某個值時,用這組指針可以快速將該值從后續的候選單中刪除。
    ??
    ?? lv_badvalue NUMBER;
    BEGIN
    ?
    /*
    ?? ---- junsansi's sample
    ?? s(1):= '7? 25? 98' ;
    ?? s(2):= '? 6??? 1 ' ;
    ?? s(3):= '?? 61 3? ' ;
    ?? s(4):= '9??? 1?? ' ;
    ?? s(5):= '??? 8 4 9' ;
    ?? s(6):= '? 75 28 1' ;
    ?? s(7):= ' 94? 3?? ' ;
    ?? s(8):= '??? 4923 ' ;
    ?? s(9):= '61???? 4 ' ;
    ?
    ?? --- sample one
    ?? s(1):= '3 58? 176';
    ?? s(2):= '1?? 5?? 2';
    ?? s(3):= '????? 549';
    ?? s(4):= ' 52 986? ';
    ?? s(5):= '43? 12? 7';
    ?? s(6):= '?? 5? 4? ';
    ?? s(7):= '5?? 6 894';
    ?? s(8):= ' 69 7?? 5';
    ?? s(9):= '?? 9?? 61';
    */
    ?
    ?? --- AlEscargot, the most complex SUDOKU puzzle ever
    ?? s(1):= '1??? 7 9 ' ;
    ?? s(2):= ' 3? 2?? 8' ;
    ?? s(3):= '? 96? 5? ' ;
    ?? s(4):= '? 53? 9? ' ;
    ?? s(5):= ' 1? 8?? 2' ;
    ?? s(6):= '6??? 4?? ' ;
    ?? s(7):= '3????? 1 ' ;
    ?? s(8):= ' 4????? 7' ;
    ?? s(9):= '? 7?? 3? ' ;
    ?
    ?? slot_values.EXTEND(9);? ----- 對VARRAY數組(第一維)進行初始化
    ?
    ?? FOR i IN 1..9 LOOP
    ?????? IF p_str IS NOT NULL THEN
    ????????? s(i):= SUBSTR(p_str,(i-1)*9+1,9);
    ?????? END IF;
    ?
    ?????? slot_values(i) := t2_num();????? ----- 對VARRAY數組(第二維)進行初始化
    ?????? slot_values(i).EXTEND(9);
    ?????? FOR j IN 1..9 LOOP
    ?????????? slot_values(i)(j) := empty_set;?????????????? -- 為每個坐標賦予完整的候選數字清單
    ?????? END LOOP;
    ?? END LOOP;
    ??
    ?
    ?? DELETE sudoku_slots;
    ??
    ?? FOR i IN 1..9 LOOP
    ?????? FOR j IN 1..9 LOOP
    ?????????? IF SUBSTR(s(i),j,1) BETWEEN '1' AND '9' THEN
    ????????????? k := TO_NUMBER(SUBSTR(s(i),j,1));
    ?????????????
    ????????????? FOR v_del IN 1..9 LOOP?????? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除。slot_values將成為稀疏數組
    ????????????????? slot_values(i)(v_del).DELETE(k);
    ????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????? END LOOP;
    ?
    ?????????? ELSE
    ????????????? ------ 發現一個未填的空單元
    ????????????? INSERT INTO sudoku_slots (r,c,a) VALUES (i,j,(CEIL(i/3)-1)*3 + CEIL(j/3));
    ?
    ?????????? END IF;
    ?????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue :=1;
    ?? WHILE v_continue = 1 LOOP
    ???????? ---- 對空單元進行篩選,如果只有一個候選數字則視為已知答案,從空單元清單中刪除
    ?
    ???????? v_continue := 0;
    ????????
    ???????? FOR lv_rec IN (SELECT * FROM sudoku_slots) LOOP
    ???????????? v_idx := slot_values(lv_rec.r)(lv_rec.c).COUNT;
    ?????????????? IF v_idx = 0 THEN
    ????????????????? RAISE_APPLICATION_ERROR(-20001,'invalid sudoku at '||lv_rec.r||','||lv_rec.c);
    ?????????????? ELSIF v_idx = 1 THEN
    ????????????????? i := lv_rec.r;
    ????????????????? j := lv_rec.c;
    ????????????????? k := slot_values(i)(j).FIRST;
    ?????????????????
    ????????????????? FOR v_del IN 1..9 LOOP? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除
    ????????????????????? slot_values(i)(v_del).DELETE(k);
    ????????????????????? slot_values(v_del)(j).DELETE(k);
    ????????????????????? slot_values((CEIL(i/3)-1)*3+CEIL(v_del/3))((CEIL(j/3)-1)*3+MOD(v_del-1,3)+1).DELETE(k);
    ????????????????? END LOOP;
    ?????????????????
    ????????????????? v_continue := 1;??? ---- 繼續循環,因為本次刪除可能導致產生新的已知單元格
    ????????????????? s(i) := SUBSTR(s(i),1,j-1) ||k|| SUBSTR(s(i),j+1);
    ?????????????????
    ????????????????? DELETE sudoku_slots WHERE r=lv_rec.r AND c=lv_rec.c; ---- 本單元格已經非空,可以刪除
    ?????????????? ELSE
    ????????????????? UPDATE sudoku_slots SET cnt = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ?????????????? END IF;
    ??????????????
    ???????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue := 1;
    ?
    ?? v_idx := 0;
    ?
    ?? deleted_by := slot_values;???? ---- 初始化為零
    ?
    ?? ---- 對空單元格進行排序。排序原則是優先取所在的行、列、區空位最少的單元
    ?? WHILE v_continue >0 LOOP
    ???????? v_continue := 0;
    ?
    ???????? FOR lv_rec IN (SELECT r,c,a
    ????????????????????????????? ,LEAST(r_cnt,c_cnt,a_cnt) AS cnt1
    ????????????????????????????? ,r_cnt+c_cnt+a_cnt cnt2
    ????????????????????????????? ,cnt
    ???????????????????????? FROM (SELECT r,c,a,cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY r) AS r_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY c) AS c_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY a) AS a_cnt
    ???????????????????????????????? FROM sudoku_slots
    ??????????????????????????????? WHERE sort_order IS NULL
    ??????????????????????????????? )
    ??????????????????????? ORDER BY cnt1,cnt2,cnt--,r,c
    ??????????????????????? )
    ???????? LOOP
    ???????????? v_idx := v_idx +1;
    ???????????? UPDATE sudoku_slots SET sort_order = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ???????????? v_continue := 1;
    ????????????
    ???????????? FOR i IN 1..9 LOOP
    ???????????????? IF NOT slot_values(lv_rec.r)(lv_rec.c).EXISTS(i) THEN
    ??????????????????? deleted_by(lv_rec.r)(lv_rec.c)(i) := NULL;?????????? ----- 如果本來沒有候選值則置為NULL
    ???????????????? END IF;
    ???????????? END LOOP;
    ?
    ???????????? SELECT *??? ------ 一組指針,指向本空位后續的空位,它們和本空格位于同一行或列或區
    ????????????? BULK COLLECT INTO pointers(v_idx)
    ????????????? FROM sudoku_slots
    ???????????? WHERE sort_order IS NULL???? ----- sort_order為空表示后續的空位, 前面的都有值了
    ?????????????????? AND (r = lv_rec.r OR c = lv_rec.c OR a=lv_rec.a);
    ????????????
    ???????????? EXIT;
    ???????? END LOOP;
    ?
    ?? END LOOP;
    ?
    ?? ---- 把排好序的數據載入內存數組
    ?? SELECT *
    ???? BULK COLLECT INTO empty_slots
    ???? FROM sudoku_slots
    ???? ORDER BY sort_order;
    ?
    ?? v_continue := 1;
    ??
    ?? IF empty_slots.COUNT>0 THEN
    ?
    ????? v_idx := 1;???? --- 取第一個空單元格
    ????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST;? ---- 取出此位置的第一個候選值
    ?
    ????? WHILE v_idx <= empty_slots.COUNT LOOP?? ---- 遍歷所有空單元格, 主循環(最為耗時)開始
    ??????????? IF empty_slots(v_idx).idx IS NOT NULL THEN?????
    ?????????????? k := empty_slots(v_idx).idx;??? ---- 因為我采用位圖的數據結構,位置即候選值。slot_values(i)(j)(k)存什么值無所謂,本例中恒為0
    ?????????????????
    ?????????????? lv_badvalue :=0;
    ?
    ?????????????? FOR v_del IN 1..pointers(v_idx).COUNT LOOP? ---- 把數字K從后續單元格的候選清單中刪除
    ?????????????????? IF slot_values(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c).EXISTS(k) THEN???? --- 該位置有值,必須刪除
    ????????????????????? IF slot_values(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c).COUNT=1 THEN??? -- 只剩下唯一一個值,不可刪除. 說明當前值K是不可行的
    ???????????????????????? FOR i IN 1..v_del-1 LOOP??? ---- 把前面已刪的補回去
    ???????????????????????????? IF deleted_by(pointers(v_idx)(i).r)(pointers(v_idx)(i).c)(k) = v_idx THEN
    ??????????????????????????????? slot_values(pointers(v_idx)(i).r)(pointers(v_idx)(i).c)(k) :=0;
    ???????????????????????????? END IF;
    ???????????????????????? END LOOP;
    ???????????????????????? lv_badvalue :=1;??????? --- 標志位說明K不可用
    ???????????????????????? EXIT;
    ????????????????????? ELSE
    ???????????????????????? slot_values(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c).DELETE(k);???? -- 候選值多于一個,所以可把K剔除
    ???????????????????????? deleted_by(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c)(k) := v_idx;??? -- 此標記表明K是被v_idx節點刪除的
    ????????????????????? END IF;
    ?????????????????????
    ?????????????????? END IF;
    ?????????????? END LOOP;
    ?
    ?????????????? IF lv_badvalue =0 THEN
    ?
    ????????????????? v_idx := v_idx+1;??? ---- 找到一個未用過的值,繼續下一個空單元格
    ?????
    ????????????????? IF v_idx >empty_slots.COUNT THEN????? ----- 所有空單元格都已處理完,答案找到了
    ???????????????????? EXIT;
    ????????????????? END IF;
    ????????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST; ---- 取出新位置的第一個候選值
    ?????????????? ELSE
    ????????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).NEXT(k);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?????????????? END IF;
    ?
    ??????????? ELSE??? ---- 指針到了末尾,所有值都不可用,必須退回到上一單元格
    ?
    ?????????????? v_idx := v_idx-1;???? --- 退回到上一單元格
    ?????????????? IF v_idx =0 THEN????? ----- 無處可退,此題沒有答案
    ????????????????? v_continue := 0;
    ????????????????? EXIT;
    ?????????????? END IF;
    ?
    ?????????????? ----- 回到上一單元格,當前值證明不行,必須釋放它并置為未用
    ?????????????? k := empty_slots(v_idx).idx;
    ?
    ?????????????? FOR v_del IN 1..pointers(v_idx).COUNT LOOP? ---- 把數字K加回候選單
    ?????????????????? IF deleted_by(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c)(k) = v_idx THEN???? -- 此值是被當前空位所刪除的,必須加回去
    ????????????????????? slot_values(pointers(v_idx)(v_del).r)(pointers(v_idx)(v_del).c)(k) :=0;
    ?????????????????? END IF;
    ?
    ?????????????? END LOOP;
    ?
    ?????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).NEXT(k);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?
    ??????????? END IF;
    ????? END LOOP;
    ?
    ?? END IF;
    ?
    ?? IF v_continue = 1 THEN
    ?
    ????? FOR v_idx IN 1..empty_slots.COUNT LOOP?????????? --取出空單元格里面填好的值,拼回字符串
    ??????????? i := empty_slots(v_idx).r;
    ??????????? j := empty_slots(v_idx).c;
    ??????????? k := empty_slots(v_idx).idx;
    ??????????? s(i) := SUBSTR(s(i),1,j-1) || k || SUBSTR(s(i),j+1);
    ?
    ????? END LOOP;
    ?
    ????? DBMS_OUTPUT.PUT_LINE('Answer Found:');
    ????? FOR i IN 1..9 LOOP? ------ 輸出答案
    ????????? DBMS_OUTPUT.PUT_LINE(s(i));
    ????? END LOOP;
    ?? ELSE
    ????? DBMS_OUTPUT.PUT_LINE('No Answer Found!');
    ?
    ?? END IF;
    ?
    END;
    /
    ?
    ?
    5、sudoku5.sql
    ?
    ??? <五毒俱全的算法程序>
    ?
    ?
    CREATE GLOBAL TEMPORARY TABLE sudoku_slots (
    ??????????? r?????????? NUMBER
    ?????????? ,c?????????? NUMBER?????
    ?????????? ,a?????????? NUMBER?????
    ?????????? ,cnt???????? NUMBER
    ?????????? ,idx???????? NUMBER
    ?????????? ,sort_order? NUMBER
    ?????????? ,s_type????? NUMBER
    ?????????? ,s_type2???? NUMBER
    ?????????? ,extra_rule? NUMBER
    ? ) ON COMMIT PRESERVE ROWS
    /
    ?

    CREATE OR REPLACE PROCEDURE sudoku5(p_str IN VARCHAR2 DEFAULT NULL)
    AS
    ?? TYPE t_num IS TABLE OF NUMBER;
    ?
    ?? TYPE t2_num IS VARRAY(21) OF t_num;
    ?? TYPE t3_num IS VARRAY(21) OF t2_num;
    ??
    ?? TYPE t_str IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
    ?
    ?? s t_str;????? ---- 字符串數組,存放題目
    ?
    ?? slot_values t3_num := t3_num();? --- 為每個單元格存放候選數字。每個坐標對應一系列標志位,如果slot_values(i)(j)(k)有值則k為i行j列的候選值
    ??????????????????????? --- 只對空單元有意義
    ??
    ?? v_idx? NUMBER;?????? -- 用于遍歷空單元格的指針變量
    ?
    ?? i? NUMBER;?????????? --- 臨時變量
    ?? j? NUMBER;
    ?? k? NUMBER;
    ?
    ?? empty_set? t_num := t_num(0,0,0,0,0,0,0,0,0);
    ?
    ?? TYPE t_sudoku_slots IS TABLE OF sudoku_slots%ROWTYPE;
    ?? empty_slots t_sudoku_slots;??? --- 存放空單元格,此數組中每個元素表示一個坐標, 以及一個指向候選值數組的指針。根據坐標及指針可到slot_values取候選值
    ??
    ?? v_continue NUMBER;
    ?
    ?? deleted_by t3_num := t3_num(); ----如果某單元的某值被它的上級刪除,則這里存放著上級單元的編號
    ?
    ?? TYPE t_ptr IS TABLE OF t_sudoku_slots INDEX BY BINARY_INTEGER;
    ?
    ?? pointers t_ptr;????? --- 對應于empty_slots中的每個空單元格,這組指針指向其后續空位,而且和本節點是處于同一行或列或區的
    ??????????????????????? --- 當這個空位取某個值時,用這組指針可以快速將該值從后續的候選單中刪除。
    ?
    ?? lv_badvalue NUMBER;
    ??
    ?? k2 NUMBER;
    ?
    ?? PROCEDURE cleanout_value_regular (r number,c number, k number, r_offset number, c_offset number)
    ?? AS
    ?? BEGIN
    ???? ----- 標準數獨,把已知值從其它格子的候選值清單中清除
    ???? FOR v_del IN 1..9 LOOP?????? ---- 把數字K從本列、本行、本區域中所有單元格的候選清單中刪除。slot_values將成為稀疏數組
    ???????? slot_values(r)(v_del+c_offset).DELETE(k);
    ???????? slot_values(v_del+r_offset)(c).DELETE(k);
    ???????? slot_values((CEIL((r-r_offset)/3)-1)*3+CEIL(v_del/3)+r_offset)((CEIL((c-c_offset)/3)-1)*3+MOD(v_del-1,3)+1+c_offset).DELETE(k);
    ???? END LOOP;
    ??
    ?? END cleanout_value_regular;
    ?
    ?? PROCEDURE cleanout_value_seq (r number,c number, k number, r_offset number, c_offset number)
    ?? AS
    ?? BEGIN
    ???? ------ 左上角的連續數獨,從上下左右的鄰居中清除連續數
    ???? IF r BETWEEN 1+r_offset AND 9+r_offset AND c BETWEEN 1+c_offset AND 9+c_offset THEN
    ??????? slot_values(r)(c).DELETE(CASE WHEN k=1 THEN 9 ELSE k-1 END);
    ??????? slot_values(r)(c).DELETE(CASE WHEN k=9 THEN 1 ELSE k+1 END);
    ???? END IF;
    ?? END cleanout_value_seq;
    ?
    ?? PROCEDURE cleanout_value_horse (r number,c number, k number, r_offset number, c_offset number)
    ?? AS
    ?? BEGIN
    ???? ----左下角的馬步數獨,從馬步格子中的候選值清單中刪除已知數
    ???? IF r BETWEEN 1+r_offset AND 9+r_offset AND c BETWEEN 1+c_offset AND 9+c_offset THEN
    ??????? slot_values(r)(c).DELETE(k);
    ???? END IF;
    ?? END cleanout_value_horse;
    ?
    ?? PROCEDURE cleanout_value_border (r number,c number, k number, r_offset number, c_offset number, a number)
    ?? AS
    ?? BEGIN
    ???? ------ 右下角的邊界數獨,上下左右的鄰居如果處于不同區域中(邊界)則刪除同為合/素數的候選數字
    ???? IF r BETWEEN 1+r_offset AND 9+r_offset AND c BETWEEN 1+c_offset AND 9+c_offset AND (CEIL(r/3)-1)*3 + CEIL(c/3)<>a THEN
    ??????? IF k IN (2,3,5,7) THEN
    ?????????? slot_values(r)(c).DELETE(2);
    ?????????? slot_values(r)(c).DELETE(3);
    ?????????? slot_values(r)(c).DELETE(5);
    ?????????? slot_values(r)(c).DELETE(7);
    ??????? ELSE
    ?????????? slot_values(r)(c).DELETE(4);
    ?????????? slot_values(r)(c).DELETE(6);
    ?????????? slot_values(r)(c).DELETE(8);
    ?????????? slot_values(r)(c).DELETE(9);
    ??????? END IF;
    ???????
    ???? END IF;
    ?? END cleanout_value_border;
    ?
    ??
    ?? PROCEDURE cleanout_value (r number,c number, k number)
    ?? AS
    ????? a NUMBER;
    ?? BEGIN
    ????? --- 在位置r,c有已知值k, 將k從其它格子的候選值清單中清除。
    ????? IF r BETWEEN 1 AND 9 AND c BETWEEN 1 AND 9 THEN??????????? ----- 左上角:不連續數獨
    ???????? cleanout_value_regular(r,c,k,0,0);
    ?
    ???????? -- 要求上下左右相鄰的格之間的數字不連續,另外1的相鄰數為2和9,9的相鄰數為8和1 。
    ???????? cleanout_value_seq(r-1,c,k,0,0);
    ???????? cleanout_value_seq(r+1,c,k,0,0);
    ???????? cleanout_value_seq(r,c-1,k,0,0);
    ???????? cleanout_value_seq(r,c+1,k,0,0);
    ????????
    ????? END IF;
    ?
    ????? IF r BETWEEN 1 AND 9 AND c BETWEEN 13 AND 21 THEN??????????? ----- 右上角:無緣數獨
    ???????? cleanout_value_regular(r,c,k,0,12);
    ?
    ???????? -- 要求每個格子中的數字與其相鄰(包括斜線)的八個格子中的數字都不能相同。
    ???????? FOR i IN GREATEST(r-1,1)..LEAST(r+1,9) LOOP
    ???????????? FOR j IN GREATEST(c-1,13)..LEAST(c+1,21) LOOP
    ???????????????? IF i<>r OR j<>c THEN
    ??????????????????? slot_values(i)(j).DELETE(k);
    ???????????????? END IF;
    ???????????? END LOOP;
    ???????? END LOOP;
    ????????
    ????? END IF;
    ?
    ????? IF r BETWEEN 7 AND 15 AND c BETWEEN 7 AND 15 THEN??????????? ----- 中? 部:標準數獨
    ???????? cleanout_value_regular(r,c,k,6,6);
    ????? END IF;
    ?
    ????? IF r BETWEEN 13 AND 21 AND c BETWEEN 1 AND 9 THEN??????????? ----- 左下角:無馬數獨
    ???????? cleanout_value_regular(r,c,k,12,0);
    ?
    ???????? --要求每個格子中的數字與其成馬步(前進二拐一)的八個格子中的數字都不能相同。
    ???????? cleanout_value_horse(r-2,c-1,k,12,0);
    ???????? cleanout_value_horse(r-2,c+1,k,12,0);
    ???????? cleanout_value_horse(r+2,c-1,k,12,0);
    ???????? cleanout_value_horse(r+2,c+1,k,12,0);
    ???????? cleanout_value_horse(r-1,c-2,k,12,0);
    ???????? cleanout_value_horse(r-1,c+2,k,12,0);
    ???????? cleanout_value_horse(r+1,c-2,k,12,0);
    ???????? cleanout_value_horse(r+1,c+2,k,12,0);
    ???????????
    ????? END IF;
    ?
    ????? IF r BETWEEN 13 AND 21 AND c BETWEEN 13 AND 21 THEN??????????? ----- 右下角:邊界數獨
    ???????? cleanout_value_regular(r,c,k,12,12);
    ?
    ???????? -- 要求任意兩個相鄰的九宮格的邊界部位,不能同為質數(2、3、5、7)或同為合數(4、6、8、9),只能是不同類的數相連(行或列),1既不是質數也不是合數,可與任何數相連。???
    ????????
    ???????? IF k<>1 THEN
    ??????????? a :=? (CEIL(r/3)-1)*3 + CEIL(c/3);???????? ----- 根據行列坐標換算所處區域, 用于判斷是否邊界
    ??????????? cleanout_value_border(r-1,c,k,12,12,a);
    ??????????? cleanout_value_border(r+1,c,k,12,12,a);
    ??????????? cleanout_value_border(r,c-1,k,12,12,a);
    ??????????? cleanout_value_border(r,c+1,k,12,12,a);
    ???????? END IF;
    ????? END IF;
    ???
    ???
    ?? END cleanout_value;
    ?
    ?? PROCEDURE remove_value (r NUMBER,c NUMBER,k NUMBER, deleted_by_idx NUMBER, p_bad_value IN OUT NUMBER)
    ?? IS
    ?? BEGIN
    ????? --- 從位置r,c的候選值清單中刪除值k
    ????? IF p_bad_value = 1 THEN
    ???????? RETURN;
    ????? END IF;
    ?????
    ????? IF slot_values(r)(c).EXISTS(k) THEN???? --- 該位置有值
    ???????? IF slot_values(r)(c).COUNT=1 THEN??? -- 只剩下唯一一個值,不可刪除. 說明當前值K是不可行的
    ??????????? p_bad_value := 1;
    ??????????? RETURN;
    ???????? ELSE
    ??????????? slot_values(r)(c).DELETE(k);???? -- 候選值多于一個,所以可把K剔除
    ??????????? deleted_by(r)(c)(k) := deleted_by_idx;??? -- 此標記表明K是被v_idx節點刪除的
    ???????? END IF;
    ????????
    ????? END IF;
    ?????
    ????? RETURN;
    ?? END remove_value;
    ?
    ?? PROCEDURE add_value_back (r NUMBER,c NUMBER,k NUMBER, deleted_by_idx NUMBER)
    ?? IS
    ?? BEGIN
    ????? ---- 如果位置r,c上的數字k是由前面空格deleted_by_idx刪除的,則加回候選清單
    ????? IF deleted_by(r)(c)(k) = deleted_by_idx THEN
    ???????? slot_values(r)(c)(k) :=0;
    ????? END IF;
    ?
    ?? END add_value_back;
    ?
    ?? PROCEDURE restore_deleted_value (r NUMBER,c NUMBER,k NUMBER, deleted_by_idx NUMBER, p_extra_rule NUMBER, p_s_type NUMBER)
    ?? AS
    ?? BEGIN
    ????? add_value_back(r,c,k,deleted_by_idx);
    ????? IF p_extra_rule=1 THEN
    ???????? IF p_s_type=1 THEN???? ---- 左上角的連續數獨,補回被刪除額外的數(連續值)
    ??????????? add_value_back(r,c,(CASE WHEN k=1 THEN 9 ELSE k-1 END),deleted_by_idx);
    ??????????? add_value_back(r,c,(CASE WHEN k=9 THEN 1 ELSE k+1 END),deleted_by_idx);
    ???????? ELSIF k<>1 THEN? ------ 右下角的邊界數獨,補回被刪除額外的數(同為合/素數)
    ???????????? IF k IN (2,3,5,7) THEN
    ??????????????? add_value_back(r,c,2,deleted_by_idx);
    ??????????????? add_value_back(r,c,3,deleted_by_idx);
    ??????????????? add_value_back(r,c,5,deleted_by_idx);
    ??????????????? add_value_back(r,c,7,deleted_by_idx);
    ???????????? ELSE
    ??????????????? add_value_back(r,c,4,deleted_by_idx);
    ??????????????? add_value_back(r,c,6,deleted_by_idx);
    ??????????????? add_value_back(r,c,8,deleted_by_idx);
    ??????????????? add_value_back(r,c,9,deleted_by_idx);
    ???????????? END IF;
    ???????? END IF;???????
    ????? END IF;
    ?????
    ?? END restore_deleted_value;
    ??
    BEGIN
    ?
    ?? --- sample
    ?? s( 1):= ' 8????? 3***2????? 8 ' ;
    ?? s( 2):= '9 41?? 8 *** 7?? 34 2' ;
    ?? s( 3):= ' 3? 5??? ***??? 2? 6 ' ;
    ?? s( 4):= ' 7? 286? ***? 519? 7 ' ;
    ?? s( 5):= '? 63?? 5 *** 9?? 81? ' ;
    ?? s( 6):= '?? 6?? 3 *** 3?? 2?? ' ;
    ?? s( 7):= '?? 9?? 7???? 4?? 1?? ' ;
    ?? s( 8):= ' 4? 135?? 4?? 783? 5 ' ;
    ?? s( 9):= '3???????? 2???????? 4' ;
    ?? s(10):= '******?? 5 9?? ******' ;
    ?? s(11):= '****** 52?? 79 ******' ;
    ?? s(12):= '******?? 8 2?? ******' ;
    ?? s(13):= '7???????? 5???????? 4' ;
    ?? s(14):= ' 2? 694?? 6?? 954? 1 ' ;
    ?? s(15):= '?? 5?? 1???? 5?? 1?? ' ;
    ?? s(16):= '?? 4?? 2 *** 4?? 5?? ' ;
    ?? s(17):= '? 29?? 3 *** 6?? 41? ' ;
    ?? s(18):= ' 6? 159? ***? 873? 4 ' ;
    ?? s(19):= ' 9? 4??? ***??? 9? 5 ' ;
    ?? s(20):= '8 76?? 5 *** 2?? 83 9' ;
    ?? s(21):= ' 3????? 4***6????? 7 ' ;
    ?
    ?? slot_values.EXTEND(21);? ----- 對VARRAY數組(第一維)進行初始化
    ??
    ?? FOR i IN 1..21 LOOP
    ?????? IF p_str IS NOT NULL THEN
    ????????? s(i):= SUBSTR(p_str,(i-1)*21+1,21);
    ?????? END IF;
    ?
    ?????? slot_values(i) := t2_num();????? ----- 對VARRAY數組(第二維)進行初始化
    ?????? slot_values(i).EXTEND(21);
    ?????? FOR j IN 1..21 LOOP
    ?????????? slot_values(i)(j) := empty_set;?????????????? -- 為每個坐標賦予完整的候選數字清單
    ?????? END LOOP;
    ?? END LOOP;
    ??
    ?? deleted_by := slot_values;???? ---- 初始化為零
    ?
    ?? DELETE sudoku_slots;
    ??
    ?? FOR i IN 1..21 LOOP
    ?????? FOR j IN 1..21 LOOP
    ?????????? IF SUBSTR(s(i),j,1) BETWEEN '1' AND '9' THEN
    ????????????? k := TO_NUMBER(SUBSTR(s(i),j,1));
    ????????????? cleanout_value(i,j,k);
    ?
    ?????????? ELSIF SUBSTR(s(i),j,1)<>'*' THEN
    ?????????????
    ????????????? ------ 發現一個未填的空單元
    ????????????? INSERT INTO sudoku_slots (r,c,a,s_type,s_type2)
    ????????????? VALUES (i,j,(CEIL(i/3)-1)*3 + CEIL(j/3)
    ???????????????????? ,CASE WHEN i BETWEEN 1 AND 9 AND j BETWEEN 1 AND 9 THEN 1????? ---- 根據坐標判斷屬于哪個數獨
    ?????????????????????????? WHEN i BETWEEN 1 AND 9 AND j BETWEEN 13 AND 21 THEN 2
    ?????????????????????????? WHEN i BETWEEN 13 AND 21 AND j BETWEEN 1 AND 9 THEN 4
    ?????????????????????????? WHEN i BETWEEN 13 AND 21 AND j BETWEEN 13 AND 21 THEN 5
    ?????????????????????????? ELSE 3
    ????????????????????? END
    ???????????????????? ,CASE WHEN i BETWEEN 7 AND 15 AND j BETWEEN 7 AND 15 THEN 3??? ---- 中部(標準數獨)和其它四個重疊的部分
    ????????????????????? END
    ???????????????????? );
    ?
    ?????????? END IF;
    ?????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue :=1;
    ?? WHILE v_continue = 1 LOOP
    ???????? ---- 對空單元進行篩選,如果只有一個候選數字則視為已知答案,從空單元清單中刪除
    ?
    ???????? v_continue := 0;
    ????????
    ???????? FOR lv_rec IN (SELECT * FROM sudoku_slots) LOOP
    ???????????? i:=lv_rec.r;
    ???????????? j:=lv_rec.c;
    ???????????? v_idx := slot_values(i)(j).COUNT;
    ?????????????? IF v_idx = 0 THEN
    ????????????????? RAISE_APPLICATION_ERROR(-20001,'invalid sudoku at '||lv_rec.r||','||lv_rec.c);
    ?????????????? ELSIF v_idx = 1 THEN
    ????????????????? k := slot_values(i)(j).FIRST;
    ????????????????? cleanout_value(i,j,k);
    ?
    ????????????????? v_continue := 1;??? ---- 繼續循環,因為本次刪除可能導致產生新的已知單元格
    ????????????????? s(i) := SUBSTR(s(i),1,j-1) ||k|| SUBSTR(s(i),j+1);
    ?????????????????
    ????????????????? DELETE sudoku_slots WHERE r=lv_rec.r AND c=lv_rec.c; ---- 本單元格已經非空,可以刪除
    ?????????????? ELSE
    ????????????????? UPDATE sudoku_slots SET cnt = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ?????????????? END IF;
    ??????????????
    ???????? END LOOP;
    ?? END LOOP;
    ?
    ?? v_continue := 1;
    ?
    ?? v_idx := 0;
    ?
    ?? ---- 對空單元格進行排序。排序原則是優先取所在的行、列、區空位最少的單元
    ?? WHILE v_continue >0 LOOP
    ???????? v_continue := 0;
    ?
    ???????? FOR lv_rec IN (SELECT s.*
    ????????????????????????????? ,LEAST(r_cnt,c_cnt,a_cnt) AS cnt1
    ????????????????????????????? ,r_cnt+c_cnt+a_cnt cnt2
    ???????????????????????? FROM (SELECT s.*
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY r) AS r_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY c) AS c_cnt
    ???????????????????????????????????? ,COUNT(*) OVER (PARTITION BY a) AS a_cnt
    ???????????????????????????????? FROM sudoku_slots s
    ??????????????????????????????? WHERE sort_order IS NULL
    ??????????????????????????????? ) s
    ??????????????????????? ORDER BY s_type,s_type2,cnt1,cnt2,cnt--,r,c
    ??????????????????????? )
    ???????? LOOP
    ???????????? v_idx := v_idx +1;
    ???????????? UPDATE sudoku_slots SET sort_order = v_idx WHERE r=lv_rec.r AND c=lv_rec.c;
    ???????????? v_continue := 1;
    ????????????
    ???????????? SELECT r?????? ------ 一組指針,指向本空位后續的空位,它們的取值受制于和本空格
    ?????????????????? ,c?????????
    ?????????????????? ,a?????????
    ?????????????????? ,cnt???????
    ?????????????????? ,idx???????
    ?????????????????? ,sort_order
    ?????????????????? ,s_type????
    ?????????????????? ,s_type2???
    ?????????????????? ,(CASE WHEN s_type=1 AND lv_rec.s_type=1 AND (r,c) IN ((lv_rec.r-1,lv_rec.c),(lv_rec.r+1,lv_rec.c),(lv_rec.r,lv_rec.c-1),(lv_rec.r,lv_rec.c+1))
    ??????????????????????????? OR s_type=5 AND lv_rec.s_type=5 AND (r,c) IN ((lv_rec.r-1,lv_rec.c),(lv_rec.r+1,lv_rec.c),(lv_rec.r,lv_rec.c-1),(lv_rec.r,lv_rec.c+1)) AND a<>lv_rec.a
    ???????????????????????? THEN 1
    ???????????????????????? ELSE 0
    ???????????????????? END) AS extra_rule? ---- 1(左上角)和5(右下角)需要額外的規則,清除的數字不僅僅是本身
    ????????????? BULK COLLECT INTO pointers(v_idx)
    ????????????? FROM sudoku_slots
    ???????????? WHERE sort_order IS NULL???? ----- sort_order為空表示后續的空位, 前面的都有值了
    ?????????????????? AND (s_type = lv_rec.s_type OR s_type2 = lv_rec.s_type2)
    ?????????????????? AND (r = lv_rec.r OR c = lv_rec.c OR a=lv_rec.a
    ??????????????????????? OR s_type = lv_rec.s_type AND s_type=2 AND r IN (lv_rec.r-1,lv_rec.r+1) AND c IN (lv_rec.c-1,lv_rec.c+1)?? ---- 四個對角鄰居位置
    ??????????????????????? OR s_type = lv_rec.s_type AND s_type=4 AND (r,c) IN ((lv_rec.r-2,lv_rec.c-1), ------ 八個馬步位置
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r-2,lv_rec.c+1),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r+2,lv_rec.c-1),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r+2,lv_rec.c+1),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r-1,lv_rec.c-2),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r-1,lv_rec.c+2),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r+1,lv_rec.c-2),
    ???????????????????????????????????????????????????????????????????????????? (lv_rec.r+1,lv_rec.c+2)
    ??????????????????????????????????????????????????????????????????????????? )
    ?????????????????????? )
    ?????????????????? ;
    ?
    ???????????
    ???????????? EXIT;
    ???????? END LOOP;
    ?
    ?? END LOOP;
    ?
    ?? ---- 把排好序的數據載入內存數組
    ?? SELECT *
    ???? BULK COLLECT INTO empty_slots
    ???? FROM sudoku_slots
    ???? ORDER BY sort_order;
    ?
    ?? v_continue := 1;
    ??
    ?? IF empty_slots.COUNT>0 THEN
    ?
    ????? v_idx := 1;???? --- 取第一個空單元格
    ????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST;? ---- 取出此位置的第一個候選值
    ?
    ????? WHILE v_idx <= empty_slots.COUNT LOOP?? ---- 遍歷所有空單元格, 主循環(最為耗時)開始
    ??????????? IF empty_slots(v_idx).idx IS NOT NULL THEN?????
    ?????????????? k := empty_slots(v_idx).idx;??? ---- 因為我采用位圖的數據結構,位置即候選值。slot_values(i)(j)(k)存什么值無所謂,本例中恒為0
    ?????????????????
    ?????????????? lv_badvalue :=0;
    ?
    ?????????????? FOR v_del IN 1..pointers(v_idx).COUNT LOOP? ---- 把數字K從后續單元格的候選清單中刪除
    ?????????????????? i := pointers(v_idx)(v_del).r;
    ?????????????????? j := pointers(v_idx)(v_del).c;
    ?????????????????? remove_value(i,j,k,v_idx,lv_badvalue);
    ?????????????????? IF pointers(v_idx)(v_del).extra_rule=1 THEN
    ????????????????????? IF empty_slots(v_idx).s_type=1 THEN???? ---- 左上角的連續數獨,刪除額外的數(連續值)
    ???????????????????????? remove_value(i,j,(CASE WHEN k=1 THEN 9 ELSE k-1 END),v_idx,lv_badvalue);
    ???????????????????????? remove_value(i,j,(CASE WHEN k=9 THEN 1 ELSE k+1 END),v_idx,lv_badvalue);
    ????????????????????? ELSIF k<>1 THEN? ------ 右下角的邊界數獨,刪除額外的數(同為合/素數)
    ???????????????????????? IF k IN (2,3,5,7) THEN
    ??????????????????????????? remove_value(i,j,2,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,3,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,5,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,7,v_idx,lv_badvalue);
    ???????????????????????? ELSE
    ??????????????????????????? remove_value(i,j,4,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,6,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,8,v_idx,lv_badvalue);
    ??????????????????????????? remove_value(i,j,9,v_idx,lv_badvalue);
    ???????????????????????? END IF;?????????????????????
    ????????????????????? END IF;
    ?????????????????? END IF;
    ??????????????????
    ?????????????????? IF lv_badvalue = 1 THEN
    ????????????????????? FOR i IN 1..v_del LOOP??? ---- 把前面已刪的補回去
    ????????????????????????? restore_deleted_value(pointers(v_idx)(i).r,pointers(v_idx)(i).c,k,v_idx,pointers(v_idx)(i).extra_rule,empty_slots(v_idx).s_type);
    ?
    ????????????????????? END LOOP;
    ????????????????????? EXIT;
    ?????????????????? END IF;
    ??????????????????
    ?????????????? END LOOP;
    ?
    ?????????????? IF lv_badvalue =0 THEN
    ?
    ????????????????? v_idx := v_idx+1;??? ---- 找到一個未用過的值,繼續下一個空單元格
    ?????
    ????????????????? IF v_idx >empty_slots.COUNT THEN????? ----- 所有空單元格都已處理完,答案找到了
    ???????????????????? EXIT;
    ????????????????? END IF;
    ????????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).FIRST; ---- 取出新位置的第一個候選值
    ?????????????? ELSE
    ????????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).NEXT(k);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?????????????? END IF;
    ?
    ??????????? ELSE??? ---- 指針到了末尾,所有值都不可用,必須退回到上一單元格
    ?
    ?????????????? v_idx := v_idx-1;???? --- 退回到上一單元格
    ?????????????? IF v_idx =0 THEN????? ----- 無處可退,此題沒有答案
    ????????????????? v_continue := 0;
    ????????????????? EXIT;
    ?????????????? END IF;
    ?
    ?????????????? ----- 回到上一單元格,當前值證明不行,必須釋放它并置為未用
    ?????????????? k := empty_slots(v_idx).idx;
    ?
    ?????????????? FOR v_del IN 1..pointers(v_idx).COUNT LOOP? ---- 把數字K加回候選單
    ??????????????????
    ?????????????????? restore_deleted_value(pointers(v_idx)(v_del).r,pointers(v_idx)(v_del).c,k,v_idx,pointers(v_idx)(v_del).extra_rule,empty_slots(v_idx).s_type);
    ?
    ?????????????? END LOOP;
    ?
    ?????????????? empty_slots(v_idx).idx := slot_values(empty_slots(v_idx).r)(empty_slots(v_idx).c).NEXT(k);? -- 當前值證明不可用,繼續下一個值,下輪循環將找出下一可用值
    ?
    ??????????? END IF;
    ????? END LOOP;
    ?
    ?? END IF;
    ?
    ?? IF v_continue = 1 THEN
    ?
    ????? FOR v_idx IN 1..empty_slots.COUNT LOOP?????????? --取出空單元格里面填好的值,拼回字符串
    ??????????? i := empty_slots(v_idx).r;
    ??????????? j := empty_slots(v_idx).c;
    ??????????? k := empty_slots(v_idx).idx;
    ??????????? s(i) := SUBSTR(s(i),1,j-1) || k || SUBSTR(s(i),j+1);
    ?
    ????? END LOOP;
    ?
    ????? DBMS_OUTPUT.PUT_LINE('Answer Found:');
    ????? FOR i IN 1..21 LOOP? ------ 輸出答案
    ????????? DBMS_OUTPUT.PUT_LINE(s(i));
    ????? END LOOP;
    ?? ELSE
    ????? DBMS_OUTPUT.PUT_LINE('No Answer Found!');
    ?
    ?? END IF;
    ?
    END;
    /
    ?
    /*
    -- 輸出答案:
    582469713***254619783
    964137285***679583412
    731852469***318427569
    173528694***425196378
    496371852***796348125
    258694137***831752946
    825946371698542961837
    649713528341967834251
    317285946725183275694
    ******837519624******
    ******152436798******
    ******694872315******
    759184263954871369524
    123769485167239547618
    684523719283456281793
    975438126***742815936
    412976538***563924187
    368215947***918736245
    596341872***387692451
    847692351***125478369
    231857694***694153872
    */
    ?
    ?
    ?
    ?
    ?
    ?
    posted on 2008-12-31 23:13 decode360 閱讀(210) 評論(0)  編輯  收藏 所屬分類: 06.PLSQL
    主站蜘蛛池模板: va天堂va亚洲va影视中文字幕| 久久午夜伦鲁片免费无码| 666精品国产精品亚洲 | 亚洲黄色片在线观看| 亚洲色偷偷综合亚洲AV伊人| 成年女人免费碰碰视频| 午夜免费福利小电影| 中文在线免费不卡视频| 麻豆一区二区三区蜜桃免费| 亚洲精品乱码久久久久久蜜桃图片| 亚洲视频在线观看不卡| 精品亚洲一区二区| 国产亚洲精品高清在线| 免费播放特黄特色毛片| 特级淫片国产免费高清视频| 丁香花在线观看免费观看| 99re这里有免费视频精品| 无码精品人妻一区二区三区免费看 | 亚洲中文字幕乱码熟女在线| 亚洲精品国产福利片| 婷婷亚洲久悠悠色悠在线播放| 亚洲午夜久久久久妓女影院| 亚洲精品国产自在久久 | www在线观看播放免费视频日本| 国产亚洲精品美女久久久久久下载| 亚洲一日韩欧美中文字幕在线| 亚洲最大的黄色网| 国产成人亚洲合集青青草原精品 | 四虎在线成人免费网站| 182tv免费视视频线路一二三| 99久热只有精品视频免费观看17| 国产免费爽爽视频在线观看 | 国产亚洲福利精品一区| 亚洲免费人成在线视频观看| 中文字幕精品无码亚洲字| 国产亚洲AV手机在线观看| 亚洲人成亚洲人成在线观看| 日韩va亚洲va欧洲va国产| 久久精品国产精品亚洲艾| 久久精品亚洲精品国产色婷| 亚洲婷婷天堂在线综合|