题目链接: P1074 靶形数独
题目大意: 在99的方格填数,要求每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。求最大分数。
题解思路: 这道题和八皇后的思路差不多。只是要判断的状态多一些。我们首先先一个问题,我们拿到这个99宫格就开始搜索吗?有没有可能处理一下这个9*9宫格可以剪枝?想一下我们要填的是空白方格,如果行要填的空白方格越少,那么搜索的层数就越少,搜索花的时间就越少。我们可以建一个结构体
struct Row
{
int zeroNum, lineIndex;//0的个数和行的编号
}row[10];
记录每一行的空白空格的数量然后排序即可。然后我们可以建一个三维数组记录这一行或这一列或这一九宫格中这个数有没有填过。
代码:
vis[1][x][v]:标记行是x,数字是v;
vis[2][y][v]:标记列是y,数字是v;
vis[3][g][v]:标记小九宫格序号是g,数字是v;
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100;
int map[maxn][maxn], vis[4][maxn][maxn],result,b[maxn],a[maxn][maxn];
int ans=0,flag=0;
struct Row
{
int zeroNum, lineIndex;
}row[10];
bool cmp(Row a, Row b) {
return a.zeroNum < b.zeroNum;
}
int which(int i, int j)
{
if (i <= 3)
{
if (j <= 3) return 1;
else if (j <= 6) return 2;
else return 3;
}
else if (i <= 6)
{
if (j <= 3) return 4;
else if (j <= 6) return 5;
else return 6;
}
else
{
if (j <= 3) return 7;
else if (j <= 6) return 8;
else return 9;
}
}
int point(int i, int j)
{
if (i == 1 || j == 1 || i == 9 || j == 9) return 6;
if (i == 2 || j == 2 || i == 8 || j == 8) return 7;
if (i == 3 || j == 3 || i == 7 || j == 7) return 8;
if (i == 4 || j == 4 || i == 6 || j == 6) return 9;
return 10;
}
void DFS(int count, int sum) {
if (count == 82) {//所有的空格填完
flag = 1;
result = max(result, sum);
return;
}
int x = b[count] / 9 + 1;
int y = b[count] % 9;
if (y == 0) {//y=0说明搜索到列数为9的方格,改变x和y的值。
x = b[count] / 9;
y = 9;
}
if (!map[x][y]) {
for (int i = 1; i <= 9; i++) {
int g = which(x, y);
if (!vis[1][x][i] && !vis[2][y][i] && !vis[3][g][i]) {
vis[1][x][i] = vis[2][y][i] = vis[3][g][i] = 1;//标记
DFS(count + 1, sum + i*point(x,y));
vis[1][x][i] = vis[2][y][i] = vis[3][g][i] = 0;//回溯
}
}
}
else {
DFS(count + 1, sum);
}
}
int main() {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
cin >> map[i][j];
if (map[i][j] == 0) {
row[i].zeroNum++;
row[i].lineIndex = i;
}
else {
vis[1][i][map[i][j]] = vis[2][j][map[i][j]] = vis[3][which(i, j)][map[i][j]] = 1;
}
ans += map[i][j]*point(i,j);//计算起始的分数
}
}
int num = 0;
sort(row + 1, row + 1 + 9, cmp);//排序
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
int x = row[i].lineIndex;
int y = j;
b[++num] = (x - 1) * 9 + y;//将排序后的点放入一维数组中
}
}
DFS(1, ans);
if (flag) {
cout << result << endl;
}
else {
cout << -1 << endl;
}
}