|
|
- 下面的另一写法是我试图进行优化的结果,我本来打算借鉴ORACLE连接表时用小表驱动大表的思路,在进入循环之前做个排序。试验证明对很多题型是有效的,我测的都在0.X或0.0X秒,但对那个AlEscargot题反而从0.15秒上升到5.x 秒。看来运气还是很重要,有时候答案很快就碰上了。
- 这个新写法利用SQL对内存数组(嵌套表)进行排序,总算和ORACLE有了点关系,算是一种技巧吧:
- 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;
- 我又对Anton Scheffer老兄的SQL作了些测试,有时候他的SQL也是很快的,但他自己的第一个例子却要花40来秒,还是运气问题。
- 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
- /
- DECLARE
- 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; --- in this column whether the number has been used
- used_r t2_num; --- in this row whether the number has been used
- used_a t2_num; --- in this area whether the number has been used
-
- area t2_num; ---- mapping from row, column to area
-
- slot_values t3_num;
-
- 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();
-
- v_continue NUMBER;
- v_del 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 ' ;
- --- 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 ' ;
- --- 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';
- FOR i IN 1..9 LOOP
- 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
- k := TO_NUMBER(TRIM(SUBSTR(s(i),j,1)));
- IF k>0 THEN
- used_r(i)(k) :=1;
- used_c(j)(k) :=1;
- used_a(area(i)(j))(k) :=1;
-
- FOR v_del IN 1..9 LOOP
- 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
- 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 ---- try all values for this slot
- i := empty_slots(v_idx).r;
- j := empty_slots(v_idx).c;
- k := empty_slots(v_idx).idx;
-
- 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
- used_c(j)(k) := 1;
- used_r(i)(k) := 1;
- used_a(area(i)(j))(k) :=1;
- EXIT;
- END IF;
-
- empty_slots(v_idx).idx := slot_values(i)(j).NEXT(empty_slots(v_idx).idx);
- END LOOP;
-
- IF empty_slots(v_idx).idx IS NULL THEN ---- all values tried but none is the answer
- -- slot_value_idx(v_idx) := slot_value(v_idx).FIRST; --- reset the index of this slot
-
- v_idx := empty_slots.PRIOR(v_idx); --- go back and release the last slot
- IF v_idx IS NULL THEN ----- no anwer found
- 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 ----- all slots tried and found an answer
- 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;
- /
- 后记:去这里下载了160高级题,经过比较排序和不排序预处理的解题速度,竟然是不排序的更快,唉白作优化了。
- [url]http://www.sudokufans.org.cn/shudo/download/160hard.rar[/url]
复制代码
[ 本帖最后由 newkid 于 2008-10-21 06:40 编辑 ] |
|