PL/SQL解數獨在簡單優化基礎上的改進
原始程式,改寫自這篇python解數獨的簡單優化 。
create or replace procedure sd3(a in varchar) as i int; r int; c int; r0 int; c0 int; n int; e varchar(10); begin i:=instr(a,'0'); if (i=0) then dbms_output.put_line(a); return; end if; e:='a'; r:=floor((i-1)/9)+1; c:=mod(i-1,9)+1; r0:=floor((i-1)/27)*3+1; c0:=floor(mod(i-1,9)/3)*3+1; --same row for j in 1..9 loop n:=(r-1)*9+j; if instr(e,substr(a,n,1))=0 and substr(a,n,1)<>0 then e:=e||substr(a,n,1); end if; end loop; --same col for j in 1..9 loop n:=(j-1)*9+c; if instr(e,substr(a,n,1))=0 and substr(a,n,1)<>0 then e:=e||substr(a,n,1); end if; end loop; --same blk for j in 1..9 loop n:=(r0+floor((j-1)/3)-1)*9+c0+mod(j-1,3); if instr(e,substr(a,n,1))=0 and substr(a,n,1)<>0 then e:=e||substr(a,n,1); end if; end loop; for m in 1 ..9 loop if instr(e,m)=0 then --dbms_output.put_line(substr(a,1,i-1)||'('||m||')'||substr(a,i+1)); sd3(substr(a,1,i-1)||m||substr(a,i+1)); end if; end loop; end; /
雖然把81次遍歷縮短到了27次,其實還是有很多多餘的步驟,以左上角格子為例,在列舉同行和同列時,本身都各被列舉了1次,在列舉第一個九宮時,第一列和第一行的格子又被列舉了。而且這種列舉每次呼叫函式都要重複進行。
改進思路1,把原始佈局中的未知格子的鄰居(同行、同列、同宮)一次性找出來,每次呼叫函式只要列舉這個格子的鄰居即可。每個格子都有20個鄰居。
create or replace procedure sd4(a in varchar) is type int_varray is varray(20) of int; type int_varray2 is varray(81) of int_varray; sd int_varray2:=int_varray2(); procedure init is k int; begin --find each one's 20 neibour sd.extend(81); for i in 1..81 loop sd(i):=int_varray(); sd(i).extend(20); k:=1; for j in 1..81 loop if i<>j and ((floor((i-1)/9) = floor((j-1)/9)) or (mod(i-j, 9) = 0) or (floor((i-1)/27) = floor((j-1)/27) and floor(mod(i-1,9)/3) = floor(mod(j-1,9)/3))) then sd(i)(k):=j; k:=k+1; end if; end loop; dbms_output.put_line(''); end loop; end; procedure sd4_inner(a in varchar) as i int; n int; e varchar(10); begin i:=instr(a,'0'); if (i=0) then dbms_output.put_line(a); return; end if; e:='a'; --lookup in 20 neibour for j in 1..20 loop n:=sd(i)(j); if instr(e,substr(a,n,1))=0 and substr(a,n,1)<>0 then e:=e||substr(a,n,1); end if; end loop; for m in 1 ..9 loop if instr(e,m)=0 then --dbms_output.put_line(substr(a,1,i-1)||'('||m||')'||substr(a,i+1)); sd4_inner(substr(a,1,i-1)||m||substr(a,i+1)); end if; end loop; end; begin init; sd4_inner(a); end; /
改進思路2,上述20個鄰居中,有些是已知的,有些是未知的。已知的不會變化,所以只要記得它們包含的數字,未知的每次嘗試不同的數字時會變化,需要遍歷。
create or replace procedure sd5(a in varchar) is type int_varray3 is varray(81) of varchar(10); ex int_varray3:=int_varray3(); type int_varray is varray(20) of int; type int_varray2 is varray(81) of int_varray; sd int_varray2:=int_varray2(); procedure init is k int; begin --find each one's 20 neibour sd.extend(81); ex.extend(81); for i in 1..81 loop sd(i):=int_varray(); sd(i).extend(20); k:=1; for j in 1..81 loop if i<>j and ((floor((i-1)/9) = floor((j-1)/9)) or (mod(i-j, 9) = 0) or (floor((i-1)/27) = floor((j-1)/27) and floor(mod(i-1,9)/3) = floor(mod(j-1,9)/3))) then if substr(a,j,1)='0' then sd(i)(k):=j; k:=k+1; elsif instr(ex(i),substr(a,j,1))=0 or instr(ex(i),substr(a,j,1)) is null then ex(i):=ex(i)||substr(a,j,1); end if; end if; end loop; dbms_output.put_line(''); end loop; end; procedure sd5_inner(a in varchar) as i int; n int; e varchar(10); begin i:=instr(a,'0'); if (i=0) then dbms_output.put_line(a); return; end if; e:='a'||ex(i); --lookup in 20 neibour for j in 1..20 loop n:=sd(i)(j); if n is null then exit; end if; if instr(e,substr(a,n,1))=0 and substr(a,n,1)<>0 then e:=e||substr(a,n,1); end if; end loop; for m in 1 ..9 loop if instr(e,m)=0 then --dbms_output.put_line(substr(a,1,i-1)||'('||m||')'||substr(a,i+1)); sd5_inner(substr(a,1,i-1)||m||substr(a,i+1)); end if; end loop; end; begin init; sd5_inner(a); end; /
執行結果比較:
SQL> exec sd5('800000000003600000070090200050007000000045700000100030001000068008500010090000400') 812753649943682175675491283154237896369845721287169534521974368438526917796318452 PL/SQL 過程已成功完成。 已用時間: 00: 00: 17.02 SQL> exec sd4('800000000003600000070090200050007000000045700000100030001000068008500010090000400') 812753649943682175675491283154237896369845721287169534521974368438526917796318452 PL/SQL 過程已成功完成。 已用時間: 00: 00: 21.41 SQL> exec sd3('800000000003600000070090200050007000000045700000100030001000068008500010090000400') 812753649943682175675491283154237896369845721287169534521974368438526917796318452 PL/SQL 過程已成功完成。 已用時間: 00: 00: 40.65
相關文章
- python解數獨的簡單優化Python優化
- MySQL效能優化之簡單sql改寫MySql優化
- PL/SQL 基礎SQL
- 袋鼠雲數棧基於CBO在Spark SQL優化上的探索SparkSQL優化
- SQL優化基礎SQL優化
- msyql 簡單的sql優化SQL優化
- C++在C的基礎上改進了哪些細節C++
- sql改寫優化:簡單規則重組實現SQL優化
- 原創:oracle PL/SQL程式設計基礎 上OracleSQL程式設計
- 對一條基於分割槽的簡單SQL的優化SQL優化
- PL/SQL 事務持久化異常 / PL/SQL commit優化SQL持久化MIT優化
- sql優化基礎視訊SQL優化
- greenplum 簡單sql優化案例SQL優化
- PL/SQL中繫結變數使用的簡單測試SQL變數
- MySQL幾個簡單SQL的優化MySql優化
- 改進版的python求解數獨Python
- Oracle PL/SQL語言基礎OracleSQL
- pl/sql程式設計基礎SQL程式設計
- PL/SQL優化一例SQL優化
- 用pl/sql解決芬蘭數學家因卡拉設計的最難數獨SQL
- pl/sql中的forall簡單測試SQL
- SQL改寫優化SQL優化
- 改進資料庫效能-SQL查詢優化資料庫SQL優化
- 34條簡單的SQL優化準則SQL優化
- PLSQL Language Reference-PL/SQL概覽-PL/SQL語言基礎SQL
- fixtrue基礎之params引數實現簡單引數化
- PL/SQL基礎語法入門SQL
- Oracle之PL/SQL基礎學習OracleSQL
- Oracle PL/SQL語言基礎(轉)OracleSQL
- 儘量用簡單的SQL替代PL/SQL邏輯SQL
- uniapp js 數獨小遊戲 寫死的簡單數獨 數獨 3.0APPJS遊戲
- MySQL管理與優化(1):SQL基礎MySql優化
- PLSQL Language Reference-PL/SQL語言基礎-詞彙單元-宣告SQL
- Mysql 效能優化--基礎引數MySql優化
- 每秒執行6000的簡單SQL優化(一)SQL優化
- 每秒執行6000的簡單SQL優化(二)SQL優化
- 【中亦安圖】SQL優化之基於SQL特徵的改寫(9)SQL優化特徵
- Oracle PL/SQL 優化與調整 – PL/SQL Native Compilation 說明OracleSQL優化