1447 靶形数独
题目大意
需要完成一个数独,不过每个格子都有一个分值,最终的得分为每个格子的分值与填在相应格上数字的乘积之和,求最大得分。
知识要点
搜索、剪枝
解题思路
使用二维数组存储每个格子所在的九宫格编号,为每行每列每个九宫格中已经出现的数字打标记,搜索时应该先确定当前可填数字方案数最少的格子。
参考代码
cpp
#include <bits/stdc++.h>
using namespace std;
int point[10][10] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 6, 6, 6, 6, 6, 6, 6, 6, 6,
0, 6, 7, 7, 7, 7, 7, 7, 7, 6,
0, 6, 7, 8, 8, 8, 8, 8, 7, 6,
0, 6, 7, 8, 9, 9, 9, 8, 7, 6,
0, 6, 7, 8, 9, 10, 9, 8, 7, 6,
0, 6, 7, 8, 9, 9, 9, 8, 7, 6,
0, 6, 7, 8, 8, 8, 8, 8, 7, 6,
0, 6, 7, 7, 7, 7, 7, 7, 7, 6,
0, 6, 6, 6, 6, 6, 6, 6, 6, 6
};
int gong[10][10] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
0, 7, 7, 7, 8, 8, 8, 9, 9, 9
};
int n, ans = -1;
bool h[10][10], l[10][10], g[10][10]; //行列九宫格标记
struct {
int x, y, v;
} P[100]; //待填格子
void DFS(int d, int sum) {
if(d == n) {
if(ans < sum) ans = sum;
return;
}
int t = 10, k, x, y, c; //找可填数字方案数最少的格子
for(int i = 0; i < n; i++) {
if(P[i].v) continue;
x = P[i].x, y = P[i].y, c = 0;
for(int j = 1; j <= 9; j++) if(!h[x][j] && !l[y][j] && !g[gong[x][y]][j]) c++;
if(t > c) t = c, k = i;
}
x = P[k].x, y = P[k].y, c = gong[x][y];
P[k].v = 1; //标记已填
for(int j = 1; j <= 9; j++) if(!h[x][j] && !l[y][j] && !g[c][j]) {
h[x][j] = l[y][j] = g[c][j] = 1;
DFS(d + 1, sum + j * point[x][y]);
h[x][j] = l[y][j] = g[c][j] = 0;
}
P[k].v = 0; //恢复未填
}
int main() {
int t, sum = 0;
for(int i = 1; i <= 9; i++) for(int j = 1; j <= 9; j++) {
scanf("%d", &t);
if(!t) P[n++] = {i, j, 0}; //存储待填格子
else h[i][t] = l[j][t] = g[gong[i][j]][t] = 1, sum += t * point[i][j];
}
DFS(0, sum);
printf("%d\n", ans);
return 0;
}