靶形數獨是乙個經典的np完全問題,沒有多項式演算法,顯然需要搜尋,遞迴回溯會優於列舉。然而此題資料範圍大,如果樸素搜尋顯然肯定tle,於是我們就需要一些優化。
1.在搜尋中,每次我們都需要查詢當前格仔的可填數字,如果用二進位制數集儲存的話,可以大大減少執行時間。對於乙個格仔(x,y),可選數字為x行、y列、所在九宮格的可選數字集合的交集,用二進位制儲存,利用位運算實現,可過75%的資料。
具體程式見下面。
這題還有乙個方法,用dlx(dancing links)。簡單的說, dancing links 主要是用雙向十字鍊錶來儲存稀疏矩陣,來達到在搜尋
中的優化。
在搜尋問題中,所需要儲存的矩陣往往隨著遞迴的加深會變得越
來越稀疏,這種情況用dancing links
來儲存矩陣,往往可以取得非常好的
效果。dlx就是利用了雙向鍊錶的刪除和重新插入的方便快速,把矩陣不斷刪除一些行和列,回溯時再恢復,使得在遞迴回溯中得到相當快的速度。具體程式也就不實現了。這方面的典型題目就是精確覆蓋問題,很多數獨問題也可以轉化為此類問題。poj3074就可以用此方法。dlx是很通用的搜尋優化方法,有興趣的話,可以自己查詢資料,
這是一篇中文版的**。
view code
1const d:array[1..9,1..9]of longword=((1,1,1,1,1,1,1,1,1),
2 (1,2,2,2,2,2,2,2,1),
3 (1,2,3,3,3,3,3,2,1),
4 (1,2,3,4,4,4,3,2,1),
5 (1,2,3,4,5,4,3,2,1),
6 (1,2,3,4,4,4,3,2,1),
7 (1,2,3,3,3,3,3,2,1),
8 (1,2,2,2,2,2,2,2,1),
9 (1,1,1,1,1,1,1,1,1));
10 c:array[1..9,1..9]of longword=((1,1,1,2,2,2,3,3,3),
11 (1,1,1,2,2,2,3,3,3),
12 (1,1,1,2,2,2,3,3,3),
13 (4,4,4,5,5,5,6,6,6),
14 (4,4,4,5,5,5,6,6,6),
15 (4,4,4,5,5,5,6,6,6),
16 (7,7,7,8,8,8,9,9,9),
17 (7,7,7,8,8,8,9,9,9),
18 (7,7,7,8,8,8,9,9,9));
19var i,j,n,m,k,l,min,x,y:longword;
20 a:array[0..9,0..9]of longword;
21 s1,s2,s3:array[0..9]of longword;
22 p:array[0..9,0..9]of boolean;
23 bo:boolean;
24 ans:longint;
25function getnum(k:longword):longword;
26begin
27 k:=(k and $55555555)+((k shr 1)and $55555555);
28 k:=(k and $33333333)+((k shr 2)and $33333333);
29 k:=(k and $0f0f0f0f)+((k shr 4)and $0f0f0f0f);
30 k:=(k and $00ff00ff)+((k shr 8)and $00ff00ff);
31 k:=(k and $0000ffff)+((k shr 16)and $0000ffff);
32 exit(k);
33end;
34procedure getmin(var x1,y1:longword);
35var i,j,k,min,l:longword;
36begin
37 min:=maxlongint;
38for i:=1to9
do39
for j:=1to9
do40
if (a[i,j]=0) then
41begin
42 k:=s1[i] or s2[j] or s3[c[i,j]];
43 k:=k xor 511;
44 k:=getnum(k);
45if (kthen
begin min:=k;x1:=i;y1:=j;end;
46end;
47end;
48procedure go(step:longword);
49var i,j,k,l,z,t,x,y:longword;
50 bak1,bak2,bak3:array[0..9]of longword;
51begin
52if step=m+1
then
53begin
54 t:=0;
55for i:=1to9
do56
for j:=1to9
do57 t:=t+a[i,j]*(d[i,j]+5);
58if ansthen ans:=t;
59 exit;
60end;
61 getmin(x,y);
62 k:=511 xor(s1[x] or s2[y] or s3[c[x,y]]);
63while k<>0
do64
begin
65 l:=k and -k;
66 k:=k-l;
67 bak1:=s1;bak2:=s2;bak3:=s3;
68 s1[x]:=s1[x] or l;
69 s2[y]:=s2[y] or l;
70 s3[c[x,y]]:=s3[c[x,y]] or l;
71case l of
721:j:=1;
732:j:=2;
744:j:=3;
758:j:=4;
7616:j:=5;
7732:j:=6;
7864:j:=7;
79128:j:=8;
80256:j:=9;
81end;
82 a[x,y]:=j;
83 go(step+1);
84 a[x,y]:=0;
85 s1:=bak1;s2:=bak2;s3:=bak3;
86end;
87end;
88begin
89 assign(input,'
sudoku.in
');reset(input);
90 assign(output,'
sudoku.out
');rewrite(output);
91 fillchar(a,sizeof(a),0);
92 m:=81;
93for i:=1to9
do94
for j:=1to9
do95
begin
96 read(a[i,j]);
97if a[i,j]<>0
then
98begin
99 s1[i]:=s1[i] or(1 shl(a[i,j]-1));
100 s2[j]:=s2[j] or(1 shl(a[i,j]-1));
101 s3[c[i,j]]:=s3[c[i,j]] or(1 shl(a[i,j]-1));
102 dec(m);
103end;
104end;
105 ans:=-1;
106 go(1);
107 writeln(ans);
108 close(input);close(output);
109end.
NOIP2009 靶形數獨 題解
題目名稱 靶形數獨 題目 noip2009 時間限制 2000ms 空間限制 128m 問題描述 小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向z博士請教,z博士拿出了他最近發明的 靶形數獨 作為這兩個...
NOIP 2009 靶形數獨題解
題目的一些資訊就不給了,點鏈結吧。解題思路 我總結為乙個要點,乙個優化 要點 搜尋順序不能 for i 1 i 9 i for j 1 j 9 j 這樣時間複雜度過不去。如何搜尋?當做填數字一樣,每乙個格仔列舉陣列,從上到下,從左到右填過去。優化 這真的是欺負我這種沒有玩過數獨的人。從已經填數字多的...
NOIP2009 靶形數獨
爆搜沒什麼好說的。剪枝思路 一開始將每個點可能取的值的數量統計出,排序,從小到大搜 然後貪心可行性 就是剩下的地方都填9,得分10 不過在vj上測85。日。加了卡時,2e7次之內跳出,總算過了。include include include include include include inclu...