Luogu P1074 靶形数独

题目描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 $Z$ 博士请教,$Z$ 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 $9$ 格宽 $\times 9$ 格高的大九宫格中有 $9$ 个 $3$ 格宽 $\times 3$ 格高的小九宫格 $($ 用粗黑色线隔开的 $)$。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 $1$ 到 $9$ 的数字。每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。$($ 如图 $)$

上图具体的分值分布是:最里面一格 $($ 黄色区域 $)$ 为 $10$ 分,黄色区域外面的一圈 $($ 红色区域 $)$ 每个格子为 $9 $分,再外面一圈 $($ 蓝色区域 $)$ 每个格子为 $8$ 分,蓝色区域外面一圈 $($ 棕色区域 $)$ 每个格子为 $7$ 分,最外面一圈 $($ 白色区域 $)$ 每个格子为 $6$ 分,如上图所示。比赛的要求是:每个人必须完成一个给定的数独 $($ 每个给定数独可能有不同的填法 $)$,而且要争取更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 $2829$ 。游戏规定,将以总分数的高低决出胜负。

输入输出格式

输入格式:

一共 $9$ 行。每行 $9$ 个整数 $($ 每个数都在 $0-9$ 的范围内 $)$ ,表示一个尚未填满的数独方格,未填的空格用“ $0$ ”表示。每两个数字之间用一个空格隔开。

输出格式:

输出共 $1$ 行。输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数 $−1$ 。

输入输出样例

输入样例#1:

1
2
3
4
5
6
7
8
9
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

输出样例#1:

1
2829

输入样例#2:

1
2
3
4
5
6
7
8
9
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

输出样例#2:

1
2852

说明

【数据范围】

$40\%$ 的数据,数独中非 %0% 数的个数不少于 %30% 。

$80\%$ 的数据,数独中非 %0% 数的个数不少于 %26% 。

$100\%$ 的数据,数独中非 %0% 数的个数不少于 %24% 。

$NOIP\;2009$ 提高组 第四题


题解

第一眼就可以看出这是个暴力 $dfs$ 的题目。

但是写起来还是很烦的...第一次写完调好兴奋地交上去 $T$ 了五个点,所以需要一些剪枝。

这个剪枝还是蛮好想的,我们把每一行按照 $0$ 的个数排序,从少到多填,明显会快很多。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

#include<bits/stdc++.h>

using namespace std;

const int score[11][11]=
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6, 0},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6, 0},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6, 0},
{0, 6, 7, 8, 9, 10, 9, 8, 7, 6, 0},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6, 0},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6, 0},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6, 0},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};

struct h
{
int data, i;
bool operator < (const h &a) const
{
if(data != a.data)
return data < a.data;
else
return i < a.i;
}
}tot0[11];

int Map[11][11], ans = -1, next[11];
bool x[11][11], y[11][11], z[11][11];

inline int belong(int a, int b)
{
return (a - 1) / 3 * 3 + (b - 1) / 3 + 1;
}

inline void dfs(int a, int b, int s)
{
if(a == 0)
{
ans = max(ans, s);
return;
}
if(Map[a][b])
{
if(b == 9)
{
dfs(next[a], 1, s);
}
else
{
dfs(a, b + 1, s);
}
return;
}
for(register int i = 1; i <= 9; i ++)
{
if(!x[a][i] && !y[b][i] && !z[ belong(a, b) ][i])
{
Map[a][b] = i;
x[a][i] = y[b][i] = z[ belong(a, b) ][i] = true;
if(b == 9)
{
dfs(next[a], 1, s + score[a][b] * i);
}
else
{
dfs(a, b + 1, s + score[a][b] * i);
}
Map[a][b] = 0;
x[a][i] = y[b][i] = z[ belong(a, b) ][i] = false;
}
}
return;
}

int inline read()
{
int x = 0, flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')flag = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
return x * flag;
}

int main()
{
int tmp = 0;
for(register int i = 1; i <= 9; i ++)
{
tot0[i].i = i;
for(register int j = 1; j <= 9; j ++)
{
Map[i][j] = read();
if(Map[i][j] == 0)
{
tot0[i].data ++;
continue;
}
x[i][ Map[i][j] ] = true;
y[j][ Map[i][j] ] = true;
z[ belong(i, j) ][ Map[i][j] ] = true;
tmp += Map[i][j] * score[i][j];
}
}
sort(tot0 + 1, tot0 + 9 + 1);
for(register int i = 1; i <= 9; i ++)
next[tot0[i].i] = tot0[i + 1].i;
dfs(tot0[1].i, 1, tmp);
printf("%d", ans);
return 0;
}

至于为什么码风跟我现在不太一样是因为这是以前写的现在来水篇博客