题目描述
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,
Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格
高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 1 到 9 的数字。每个数字在每个小九宫格内不能
重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)
上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8 分,蓝色区域外面一圈(棕
色区域)每个格子为 7 分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。比赛的
要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和
总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。
由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。
输入输出格式
输入格式:一共 9 行。每行 9 个整数(每个数都在 0―9 的范围内),表示一个尚未填满的数独方
格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。
输出格式:输出共 1 行。
输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。
输入输出样例
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
此题很容易tle,而选择的次数和每行中“0”的次数有关,从"0“少的一行开始会使剪枝更有效。
代码中有注释
#include<bits/stdc++.h>
using namespace std;
int ma[11][11];//地图
int hang[11][11],lie[11][11],gong[11][11],num1; /*前三个二维数组中的第一维是第几行(列,宫),第二维是值,
整体反馈的是该值在这行(列,宫)中是否出现过,num1表
示的是初始图中“0”的个数*/
int book[100][5]; /*第一维指的是第几个“0”,第二维分别表示第几行,第几列,第几宫,
权值(个人不喜欢用0下标)*/
int ans=-1; //最后的答案
struct f
{
int ha; //由于需要sort得到最少“0”的行,用ha保留行数,num表示该行中有几个0;
int num;
}a[11];
int CheckGong(int x,int y) //简单的判断宫
{
if(x<=3)
{
if(y<=3)
return 1;
else if(y<=6)
return 2;
else
return 3;
}
else if(x<=6)
{
if(y<=3)
return 4;
else if(y<=6)
return 5;
else
return 6;
}
else
{
if(y<=3)
return 7;
else if(y<=6)
return 8;
else
return 9;
}
}
int zhi[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},
};
void dfs(int step,int sum) //step表示第几个已安排几个“0”,sum表示当前的权值和
{
if(step==num1) //终止条件
{
if(sum>ans)
{
ans=sum;
}
return;
}
for(int i=1;i<=9;i++)
{
if(!hang[book[step][1]][i]&&!lie[book[step][2]][i] //该“i"值必须满足在该行,该列,该宫中均未出现过
&&!gong[CheckGong(book[step][1],book[step][2])][i])
{
hang[book[step][1]][i]=lie[book[step][2]][i]=gong[book[step][3]][i]=1;
dfs(step+1,sum+i*book[step][4]);
hang[book[step][1]][i]=lie[book[step][2]][i]=gong[book[step][3]][i]=0;
}
}
}
int com(const f&a,const f&b) //sort的自定义函数
{
return a.num<b.num;
}
int main()
{
for(int i=1;i<=9;i++) //初始化a[]中储存的行
{
a[i].ha=i;
}
num1=1;
int he=0; //已知的权值和
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
cin>>ma[i][j]; //读入九宫格
if(ma[i][j]) //若非0
{
hang[i][ma[i][j]]=1; //标记行,列,宫
lie[j][ma[i][j]]=1;
gong[CheckGong(i,j)][ma[i][j]]=1;
he+=zhi[i][j]*ma[i][j]; //求出已知的权值和
}
else
{
a[i].num++; //改行中0的数量加一
}
}
}
sort(a+1,a+10,com); //排序
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
if(!ma[a[i].ha][j]) //若为0
{
book[num1][1]=a[i].ha;book[num1][2]=j; /*用book数组标记该点的行,列,宫,权值,数据,
方面后面dfs */
book[num1][3]=CheckGong(a[i].ha,j);book[num1][4]=zhi[a[i].ha][j];
num1++; //已知0数量加一
}
}
}
dfs(1,he); //由于num1从1开始,所以我们也从1开始
cout<<ans;
return 0;
}