407. [NOIP2009] 靶形数独
★★ 输入文件:
sudoku.in
输出文件:sudoku.out
简单对比
时间限制: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 2sudoku.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 6sudoku.out
2852
【数据范围】
40%的数据,数独中非 0数的个数不少于 30。
80%的数据,数独中非 0数的个数不少于 26。
100%的数据,数独中非 0 数的个数不少于 24。
这题乍一看让人感觉一脸不可做的样子
表示我的内心一脸懵逼甚至还想学 $DLX$
结果实际上打了个最为暴力的暴搜就过了...
大概搜索思路: 开三个数组保存九宫格/行/列中是否出现过某数, 然后开两个用来记录某下标的得分权值与所属九宫格编号.
然后 $DFS$ 搜索枚举每个未知位置的可能值, 枚举时根据三个数组判一下是否在该行/列/九宫格内出现过. 发现可行解后更新答案.
然后就AC了=_=...一脸懵逼.png
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <iostream> 5 #include <algorithm> 6 typedef std::pair<int,int> Point; 7 8 const int MAXN=20; 9 10 const int score[MAXN][MAXN]={{0}, 11 {0,6,6,6,6, 6,6,6,6,6}, 12 {0,6,7,7,7, 7,7,7,7,6}, 13 {0,6,7,8,8, 8,8,8,7,6}, 14 {0,6,7,8,9, 9,9,8,7,6}, 15 {0,6,7,8,9,10,9,8,7,6}, 16 {0,6,7,8,9, 9,9,8,7,6}, 17 {0,6,7,8,8, 8,8,8,7,6}, 18 {0,6,7,7,7, 7,7,7,7,6}, 19 {0,6,6,6,6, 6,6,6,6,6}}; 20 const int block[MAXN][MAXN]={{0}, 21 {0,1,1,1,2,2,2,3,3,3}, 22 {0,1,1,1,2,2,2,3,3,3}, 23 {0,1,1,1,2,2,2,3,3,3}, 24 {0,4,4,4,5,5,5,6,6,6}, 25 {0,4,4,4,5,5,5,6,6,6}, 26 {0,4,4,4,5,5,5,6,6,6}, 27 {0,7,7,7,8,8,8,9,9,9}, 28 {0,7,7,7,8,8,8,9,9,9}, 29 {0,7,7,7,8,8,8,9,9,9}}; 30 31 int ans=-1; 32 int known; 33 int unknown; 34 Point u[MAXN*MAXN]; 35 bool col[MAXN][MAXN]; 36 bool row[MAXN][MAXN]; 37 bool visited[MAXN][MAXN]; 38 39 void Initialize(); 40 void DFS(int,int); 41 42 int main(){ 43 Initialize(); 44 DFS(unknown,known); 45 printf("%d ",ans); 46 return 0; 47 } 48 49 void DFS(int rest,int sum){ 50 if(rest==0){ 51 ans=std::max(ans,sum); 52 return; 53 } 54 else{ 55 for(int i=1;i<=9;i++){ 56 if(!visited[block[u[rest].first][u[rest].second]][i]&&!row[u[rest].first][i]&&!col[u[rest].second][i]){ 57 row[u[rest].first][i]=true; 58 col[u[rest].second][i]=true; 59 visited[block[u[rest].first][u[rest].second]][i]=true; 60 DFS(rest-1,sum+score[u[rest].first][u[rest].second]*i); 61 visited[block[u[rest].first][u[rest].second]][i]=false; 62 col[u[rest].second][i]=false; 63 row[u[rest].first][i]=false; 64 } 65 } 66 } 67 } 68 69 void Initialize(){ 70 #ifndef ASC_LOCAL 71 freopen("sudoku.in","r",stdin); 72 freopen("sudoku.out","w",stdout); 73 #endif 74 int tmp; 75 for(int i=1;i<=9;i++){ 76 for(int j=1;j<=9;j++){ 77 scanf("%d",&tmp); 78 if(tmp==0){ 79 unknown++; 80 u[unknown].first=i; 81 u[unknown].second=j; 82 } 83 else{ 84 known+=tmp*score[i][j]; 85 visited[block[i][j]][tmp]=true; 86 row[i][tmp]=true; 87 col[j][tmp]=true; 88 } 89 } 90 } 91 }
日常图包w