[NOIP2009]靶形數獨 題解


407. [NOIP2009] 靶形數獨

時間限制:5 s   內存限制:128 MB

【問題描述】 
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨游戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 Z博士請教,Z 博士拿出了他最近發明的“靶形數獨” ,作為這兩個孩子比試的題目。 
靶形數獨的方格同普通數獨一樣,在 9 格寬×9 格高的大九宮格中有 9 個 3 格寬×3 格高的小九宮格(用粗黑色線隔開的) 。在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入 1到 9 的數字。每個數字在每個小九宮格內不能重復出現,每個數字在每行、每列也不能重復出現。但靶形數獨有一點和普通數獨不同,即每一個方格都有一個分值,而且如同一個靶子一樣,離中心越近則分值越高。 (如圖) 


上圖具體的分值分布是:最里面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅色區域)每個格子為 9 分,再外面一圈(藍色區域)每個格子為 8分,藍色區域外面一圈(棕色區域)每個格子為 7分,最外面一圈(白色區域)每個格子為 6 分,如上圖所示。比賽的要求是:每個人必須完成一個給定的數獨(每個給定數獨可能有不同的填法) ,而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨游戲中,總分數為 2829。游戲規定,將以總分數的高低決出勝負。 


由於求勝心切,小城找到了善於編程的你,讓你幫他求出,對於給定的靶形數獨,能夠得到的最高分數。

 【輸入】 
輸入文件名為 sudoku.in。 
一共 9 行。每行 9 個整數(每個數都在 0—9 的范圍內) ,表示一個尚未填滿的數獨方格,未填的空格用“0”表示。每兩個數字之間用一個空格隔開。 
 
【輸出】 
輸出文件 sudoku.out共 1行。 
輸出可以得到的靶形數獨的最高分數。如果這個數獨無解,則輸出整數-1。 
 
【輸入輸出樣例 1】 
sudoku.in

7 0 0 9 0 0 0 0 1 
1 0 0 0 0 5 9 0 0 
0 0 0 2 0 0 0 8 0 
0 0 5 0 2 0 0 0 3 
0 0 0 0 0 0 6 4 8 
4 1 3 0 0 0 0 0 0 
0 0 7 0 0 2 0 9 0 
2 0 1 0 6 0 8 0 4 
0 8 0 5 0 4 0 1 2

sudoku.out 

2829 

  
【輸入輸出樣例 2】 
sudoku.in

0 0 0 7 0 2 4 5 3 
9 0 0 0 0 8 0 0 0 
7 4 0 0 0 5 0 1 0 
1 9 5 0 8 0 0 0 0 
0 7 0 0 0 0 0 2 5 
0 3 0 5 7 9 1 0 8 
0 0 0 6 0 1 0 0 0 
0 6 0 9 0 0 0 0 1 
0 0 0 0 0 0 0 0 6

sudoku.out 

2852 
 
【數據范圍】 
40%的數據,數獨中非 0數的個數不少於 30。 
80%的數據,數獨中非 0數的個數不少於 26。 
100%的數據,數獨中非 0 數的個數不少於 24。  

  這道題在這里先藐視一下有160的身高卻又190的心的jhs,我第一次提交剪枝少了一些,被他嘲笑,結果A了之后還比他快了1/3,(自帶元首渣渣配音)。

  這道題其實考的是深搜和剪枝,首先,本題是要求最大值,因此以往當前ans>最小(優)ans的剪枝報廢。然后我們可以思考一下,我們並沒有必要去時常檢驗數獨,而是直接去通過bool數組去限制填數,因為搜索題有一個定律,再好的剪枝也不如在搜索時直接不去對該情況進行搜索。

  因此我們通過3個bool數組對三種情況進行限制,就會很開心的發現自己T了一個點,這時候怎么辦呢?我們可以反其道而行之,倒着搜,從某中意義上來講,如果一個題目它無意去卡你這點,他們一般都會在dfs搜到較淺層的時候就發展出很多枝;來考驗大家的剪枝能力,大家可以這樣去想,我們可以把搜索看成一個頭重腳輕的類似陀螺形狀的東西,倒着搜索是要快很多的。

 1 #include<iostream>
2 #include<cstdlib>
3 #include<cstdio>
4 #include<cstring>
5 #include<algorithm>
6 #include<map>
7 #include<queue>
8 #include<string>
9 #include<cmath>
10 using namespace std;
11 int n=9,a[15][15],ans;
12 bool fw[2][15][15],be[15][15];
13 int f[15][15],num[15][15];
14 int get(int x,int y){
15 if(x<=3&&y<=3) return 1;
16 if(x<=3&&y<=6) return 2;
17 if(x<=3&&y<=9) return 3;
18 if(x<=6&&y<=3) return 4;
19 if(x<=6&&y<=6) return 5;
20 if(x<=6&&y<=9) return 6;
21 if(x<=9&&y<=3) return 7;
22 if(x<=9&&y<=6) return 8;
23 return 9;
24 }
25 void dfs(int l,int wz,int sum){
26 if(wz==n+1)
27 {
28 if(l==1)
29 {
30 if(sum>ans) ans=sum;
31 return;
32 }
33 dfs(l-1,0,sum);
34 return;
35 }
36 int bj=0;
37 for(int i=wz+1;i<=n;i++)
38 {
39 if(!a[l][i])
40 {
41 bj=i;
42 break;
43 }
44 }
45 if(!bj)
46 {
47 dfs(l,n+1,sum);
48 return;
49 }
50 for(int i=1;i<=9;i++)
51 {
52 if(!fw[0][l][i]&&!fw[1][bj][i]&&!be[num[l][bj]][i])
53 {
54 be[num[l][bj]][i]=fw[0][l][i]=fw[1][bj][i]=1;
55 dfs(l,bj,sum+i*f[l][bj]);
56 be[num[l][bj]][i]=fw[0][l][i]=fw[1][bj][i]=0;
57 }
58 }
59 }
60 int main(){
61 int sum=0;
62 for(int i=1;i<=n;i++)
63 f[1][i]=f[i][1]=f[n][i]=f[i][n]=6;
64 for(int i=2;i<=n-1;i++)
65 f[2][i]=f[i][2]=f[n-1][i]=f[i][n-1]=7;
66 for(int i=3;i<=n-2;i++)
67 f[3][i]=f[i][3]=f[n-2][i]=f[i][n-2]=8;
68 for(int i=4;i<=n-3;i++)
69 f[4][i]=f[i][4]=f[n-3][i]=f[i][n-3]=9;
70 f[5][5]=10;
71 for(int i=1;i<=n;i++)
72 {
73 for(int j=1;j<=n;j++)
74 {
75 scanf("%d",&a[i][j]);
76 fw[0][i][a[i][j]]=1;
77 fw[1][j][a[i][j]]=1;
78 num[i][j]=get(i,j);
79 be[num[i][j]][a[i][j]]=1;
80 sum+=a[i][j]*f[i][j];
81 }
82 }
83
84 dfs(n,0,sum);
85 if(!ans) ans=-1;
86 printf("%d\n",ans);
87 // while(1);
88 return 0;
89 }
View Code

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com